解题报告:HDU 4111 Alice and Bob 递推|博弈


题意:
现在有n堆石子,每堆石子分别有A1,A2,A3...An个
现在有两种操作:
   1.选一堆非空石子将其数量减一
   2.合并两个非空石子
Alice 和 Bob 轮流进行操作,先取完的获胜,Alice先操作,问谁能获胜

思路:
首先需要发现几个性质:
1.所有给出的数据都可以转换成 (A,X)的状态。 A为石子数量为1的石子堆数目,X为其余 所有非1的石子堆
的和加上 它们的 数目 - 1。
2.如果没有石子数量为1的石子堆,那么最后的结果为 (sum+n-1)&1。
3.如果只有一个数量为1的石子堆,那么先手必胜,也就是说(1,X)必胜。

4.如果只有两个数量为1的石子堆的数目,那么此时为(2,X)的形式,为了避开给对手(1,X)的必胜局势,他一定

会选择合并两个1,或者从X中拿走一个

5.只有在(A,2)的局势下,才能转移到(A+1,0)的局势,也就是说这有一个2的局势下选择从2中拿走一个1有可能

可以改变胜负态。


注意到上面这些,那么就开始设计状态转移方程了:
当X=0: 
1.A=0 : dp[A][X]=0
(0,0)为败势

2.A<3 dp[A][X]=1
(1,0)和(2,0)都为胜势

3.else dp[A][X]=(!dp[A-2][2]) | (!dp[A-1][0])
可以合并两个1或者拿走一个1

当X!=0:
1.A=0 dp[A][X]=X&1 
当0个1的时候看X的奇偶

2.A=1 dp[A][X]=1
当1个1的时候必胜

3.else dp[A][X] = (!dp[A-1][X]) | (!dp[A-2][X+3]) | (!dp[A-1][X+1])  
三种操作分别对应着 拿走1,合并2个1,合并1和X
①X!=2 dp[A][X] |= (!dp[A][X-1]) 
从X拿走1,此时状态为(A,X-1)
②X==2 dp[A][X] |= (!dp[A+1][0]) 
同样从X拿走1,此时状态为(A+1,0)
最后的顺序需要注意(3.②)的情况,当处理(A,2)(A>0)的情况时,需先处理(A+1,0)的情况。

代码:
#include<bits/stdc++.h>

using namespace std;

bool dp[51][55005];

inline void oper(int a,int b){
    if(b==0){
        if(a==0)dp[a][b]=0;
        else if(a<3)dp[a][b]=1;
        else dp[a][0] = (!dp[a-2][2])|(!dp[a-1][0]);
        return ;
    }

    if(a==0)dp[a][b] = b&1;
    else if(a==1)dp[a][b]=1;
    else {
        dp[a][b] = (!dp[a-1][b])|(!dp[a-2][b+3])|(!dp[a-1][b+1]);
        if(b!=2)dp[a][b]|=(!dp[a][b-1]);
        else dp[a][b]|=(!dp[a+1][0]);
    }
}

void init(){
    int m = 55000;
    for(int i=0;i<=50;i++){
        for(int j=0;j<=m;j++){
            if(i&&j==2)oper(i+1,0);
            oper(i,j);
        }
    }
}

int main()
{

    init();
    int T,t=0;
    scanf("%d",&T);
    while(T--){
        int n,x;
        scanf("%d",&n);
        int ans = 0 ;
        int one = 0 ;
        while(n--){
            scanf("%d",&x);
            if(x!=1){
                if(ans)ans++;
                ans += x;
            }
            else one++;
        }
        printf("Case #%d: %s\n",++t,dp[one][ans]?"Alice":"Bob");
    }return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值