标签:
2 3 2 2 3 2 3 3
Alice Bob
有两个人Alice 和 Bob在玩一个游戏,游戏的内容就是一共有 m 堆石子,每个人有两种操作:
1.可以拿每一堆的任意数量但不能不拿;
2.可以将当前一堆的石子(当前的石子数肯定是>=2的)变为两堆;
最后谁先拿完谁赢,Alice 先手
解题思路:
首先我们看一下数据范围,S[i]<2^31-1,所以我们不能直接用SG函数,但是我们可以先进行打表,然后看一下有没有什么规律,首先我们分析一下,如果没有后边的第二种操作那么这就是一个简单的尼姆博弈,就是求一个异或值就行了,那么加上第二种操作,那么就考虑一下它的后继状态,他的后即状态,SG[i] = mex{i-1,i-2... SG[i-1]^SG[1],SG[i-2]^SG[2]};所以我们就可以通过这个后继状态来打一个表,通过这个表我们找到了一些规律,就是当x%4==0的时候,SG[x] = x-1,当x%4==3的时候,SG[x] = x+1,其他情况就是SG[x] = x;
My Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e3+5;
int sg[MAXN];
int get_SG(int x)
{
    if(sg[x]!=-1)
        return sg[x];
    int hash[MAXN];
    memset(hash, 0, sizeof(hash));
    for(int i=x-1;i>=0;i--)
        hash[get_SG(i)]=1;
    for(int j=1; j<=x/2; j++)
        hash[get_SG(x-j)^get_SG(j)]=1;
    int k;
    for(k=0; k<MAXN; k++)
    {
        if(!hash[k])
        {
            return sg[x] = k;
        }
    }
}
int main()
{
    /**测试打表**/
    /*
    memset(sg,-1,sizeof(sg));
    for(int i=0; i<50; i++)
    {
        printf("sg[%d] = %d\n",i,get_SG(i));
    }*/
    int T;
    cin>>T;
    while(T--)
    {
        int m;
        int ans = 0;
        cin>>m;
        while(m--)
        {
            int x;
            cin>>x;
            if(x%4==0)
                ans ^= (x-1);
            else if(x%4 == 3)
                ans ^= (x+1);
            else
                ans ^= x;
        }
        if(ans)
            puts("Alice");
        else
            puts("Bob");
    }
    return 0;
}
HDU 3032 Nim or not Nim?(博弈 SG打表找规律)
标签:
原文地址:http://blog.csdn.net/qingshui23/article/details/51203593