棋盘游戏&&binaryA+B<Dp,Dfs_with_Mem>

来源:互联网 发布:mac如何输入大写字母 编辑:程序博客网 时间:2024/06/06 09:44

Description

一个n*n(n>=2)棋盘上有黑白棋子各一枚。游戏者A和B轮流移动棋子,A先走。

A的移动规则:只能移动白棋子。可以往上下左右四个方向之一移动一格。

B的移动规则:只能移动黑棋子。可以往上下左右四个方向之一移动一格或者两格。

和通常的“吃子”规则一样,当某游戏者把自己的棋子移动到对方棋子所在的格子时,他就赢了。两个游戏者都很聪明,当可以获胜时会尽快获胜,只能输掉的时候会尽量拖延时间。你的任务是判断谁会赢,需要多少回合。

比如n=2,白棋子在(1,1),黑棋子在(2,2),那么虽然A有两种走法,第二个回合B总能取胜。

Input

输入仅一行,包含五个整数n, r1, c1, r2, c2,即棋盘大小和棋子位置。白色棋子在(r1,c1),黑色棋子在(r2,c2)(1<=r1,c1,r2,c2<=n)。黑白棋子的位置保证不相同。

Output

输出仅一行,即游戏结果。如果A获胜,输出WHITE x;如果B获胜,输出BLACK x;如果二者都没有必胜策略,输出DRAW。

Sample Input

输入1:

2 1 1 2 2

输入2:

2 2 2 1 2

输入3:

3 1 1 3 3

Sample Output

输出1:

BLACK 2

输出2:

WHITE 1

输出3:

BLACK 6

Data Constraint

40%的数据 n<=5

100%的数据n<=20

其实只要白棋不能一开始一口吃掉黑棋,他就输定了。
那么白棋会尽可能拖延时间。
设状态f(xWhite,yWhite,xBlack,yBlack,Control,dep),Control=1意味着这一步到白棋走

因为每走一轮两子曼哈顿距离会减少1,那么最多走4n步

转移:
白棋要拖时间,即把后继状态取一个max。
f(xWhite,yWhite,xBlack,yBlack,Control,dep)=Maxf(xnewWhite,ynewWhite,xBlack,yBlack,Control,dep+1)
黑棋不想拖时间,把后继状态取一个min
f(xWhite,yWhite,xBlack,yBlack,Control,dep)=minf(xWhite,yWhite,xnewBlack,ynewBlack,!Control,dep+1)

喔,程序写得和题解表述有点出入但意思一样。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std ;int i , j , k , n , m ;int bx , by , wx , wy ;int f[105][25][25][25][25][2] ;int d[4][2] = { 1 , 0 , -1 , 0 , 0 , 1 , 0 , -1 } ;int max( int a , int b ) {    return a > b ? a : b ;}int min( int a , int b ) {    if( a==-1 ) return b ;    if( b==-1 ) return a ;    if( a==-2 ) return b ;    if( b==-2 ) return a ;    return a < b ? a : b ;}int Discover( int dep , int bx , int by , int wx , int wy , bool b_ctr ) {    if( dep > 100 ) return -2 ;    if( f[dep][bx][by][wx][wy][b_ctr] != -1 ) return f[dep][bx][by][wx][wy][b_ctr] ;    if( bx==wx && wy==by ) {        if( b_ctr==0 ) return f[dep][bx][by][wx][wy][b_ctr] = 0 ;        return f[dep][bx][by][wx][wy][b_ctr] = -2 ;    }    if( b_ctr ) {        for( int i=0 ; i<4 ; i++ ) {            int nx = bx + 2*d[i][0] , ny = by + 2*d[i][1] ;            if( nx<=n && ny<=n && nx>0 && ny>0 ) {                f[dep][bx][by][wx][wy][1] = min( Discover( dep + 1 , nx , ny , wx , wy , 0 ) , f[dep][bx][by][wx][wy][1] ) ;            }        }        for( int i=0 ; i<4 ; i++ ) {            int nx = bx + d[i][0] , ny = by + d[i][1] ;            if( nx<=n && ny<=n && nx>0 && ny>0 ) {                f[dep][bx][by][wx][wy][1] = min( Discover( dep + 1 , nx , ny , wx , wy , 0 ) , f[dep][bx][by][wx][wy][1] ) ;            }        }    } else {        for( int i=0 ; i<4 ; i++ ) {            int nx = wx + d[i][0] , ny = wy + d[i][1] ;            if( nx<=n && ny<=n && nx>0 && ny>0 ) {                f[dep][bx][by][wx][wy][0] = max( Discover( dep+1 , bx , by , nx , ny , 1 ) , f[dep][bx][by][wx][wy][0] ) ;                if( f[ dep+1 ][ bx ][ by ][ nx ][ ny ][ 1 ]==-2 ) {                    f[dep][bx][by][wx][wy][0] =  -2 ;                        break ;                }            }        }    }    return f[dep][bx][by][wx][wy][b_ctr]<0 ? f[dep][bx][by][wx][wy][b_ctr] = -2 : ++f[dep][bx][by][wx][wy][b_ctr]  ;}int main() {    scanf("%d%d%d%d%d",&n,&wx,&wy,&bx,&by ) ;    if( abs( wx-bx ) + abs( by-wy ) == 1 ) {        puts("WHITE 1" ) ;        return 0 ;    }    memset( f , 255 , sizeof f ) ;    Discover( 0 ,bx , by , wx , wy , 0 ) ;    printf("BLACK %d",f[0][bx][by][wx][wy][0] ) ;}

Description

输入三个整数a, b, c,把它们写成无前导0的二进制整数。比如a=7, b=6, c=9,写成二进制为a=111, b=110, c=1001。接下来以位数最多的为基准,其他整数在前面添加前导0,使得a, b, c拥有相同的位数。比如在刚才的例子中,添加完前导0后为a=0111, b=0110, c=1001。最后,把a, b, c的各位进行重排,得到a’, b’, c’,使得a’+b’=c’。比如在刚才的例子中,可以这样重排:a’=0111, b’=0011, c’=1010。

你的任务是让c’最小。如果无解,输出-1。

Input

输入仅一行,包含三个整数a, b, c。

Output

输出仅一行,为c’的最小值。

Sample Input

输入1:

7 6 9

输入2:

1 1 4

输入3:

1 1 1

Sample Output

输出1:

10

输出2:

2

输出3:

-1

Data Constraint

20%的数据a,b,c<=100

40%的数据a,b,c<=1000

100%的数据a,b,c<=2^30

这题打着打着暴力就不小心打成了正解
我本来只是想打个dfs
设了状态dfs(now,dash,a,b,c)
指 当前位,是否进位,剩多少a,b,c
有了状态转移随便写。
结果发现加个记忆化似乎就是正解咯。

#include<cstdio>#include<algorithm>#include<cstring>using namespace std ;int i , j , k , n , m , a , b , c , na , nb , nc ;int A[32] , B[32] ,  C[32] ;int Bialize( int a , int *A ) {    int ret = 0 ;    for( int j = 0 ; a ; j++ , a/=2  ) ret += A[j] = a % 2 ;    return ret ;}bool JUD = 0 ;int dfn = 0 ;typedef long long ll ;ll f[33][2][33][33][33] , ans ;ll min( ll a , ll b ) {    if( a==-1 ) return b ;    if( b==-1 ) return a ;    return a < b ? a : b ;}ll dfs( int now , bool dash , int a , int  b , int c ) {    if( now>=0 && f[now][dash][a][b][c]!=0x7fffffff ) return f[now][dash][a][b][c] ;    if( now==-1 ) {        if( a==0 && b==0 && c==0 && dash==0) {            return 0 ;        }        return -1 ;    }    ll ret = -1 ;    if( dash ) {        if( a ) ret = min( ret , dfs( now-1 , 1 , a-1 , b , c ) ) ;        if( b ) ret = min( ret , dfs( now-1 , 1 , a , b-1 , c ) ) ;        if( a && b ) ret = min( ret , dfs( now-1 , 0 , a-1 , b-1 ,c ) ) ;        if( a && b && c ) {            ll tmp = dfs( now - 1  , 1 , a-1 , b-1 , c-1 ) ;            if( tmp!=-1 ) ret = min( ret , ( 1 << now ) + tmp ) ;        }    } else {        ret = min( ret , dfs( now-1 , 0 , a , b , c ) ) ;        if( c ) {            if( a ) {                ll tmp = dfs( now-1 , 0 , a-1 , b , c-1 ) ;                if( tmp !=-1 ) ret = min( ret , ( 1 << now ) + tmp ) ;            }            if( b ) {                ll tmp =  dfs( now-1 , 0 , a , b-1 , c-1 ) ;                if( tmp!=-1 ) ret = min( ret , ( 1 << now ) + tmp ) ;            }            ll tmp =  dfs( now-1 , 1 , a , b , c-1 )  ;            if( tmp!=-1 ) ret = min( ret , ( 1 << now ) + tmp ) ;        }     }    return f[now][dash][a][b][c] = ret ;}int main() {     scanf("%d%d%d", &a,&b,&c ) ;    m = c ;    na = Bialize( a , A ) , nb = Bialize( b , B ) , nc = Bialize( c , C ) ;    int tot = 0 ;     for( i=0 ; i<=31 ; i++ ) if( C[i] || A[i] || B[i] ) tot = i ;    memset( C , 0 , sizeof C ) ;    for( i=0 ; i<33 ; i++ ) for( j=0 ; j<2 ; j++ )         for( k=0 ; k<33 ; k++ ) for( int l = 0 ; l<33 ; l++ )             for( int u = 0 ; u<33 ; u++ ) f[i][j][k][l][u] = 0x7fffffff ;    ans = 0x7fffffff ;    ans = dfs( tot , 0 , na , nb , nc ) ;    if( ans == 0x7fffffff ) ans = -1 ;     printf("%lld",ans ) ;}

DEBUG LOG

写记忆化搜索一定要记住记忆化数组初值,极值的区别,建议初值给-1,极值给-2!!

调完这两个程序长经验咯

0 0
原创粉丝点击