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

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!!

调完这两个程序长经验咯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值