Matches Game POJ - 2234(尼姆博弈)

传送门

题意:给出n堆石头,现在由先手与后手进行操作,每次每个选手都可以选择一堆石子进行取出,不能不取,哪位选手面对没有石头可以取得情况就是失败了,现在先手拜输出"No",先手赢输出"Yes"。

题解:最基本的尼姆博弈,最需要了解就是必败态,到底什么是必败态。

必败态:

1.无法进行任何移动的局面是必败态

2.可以移动到必败态的局面是非必败态

3.在必败态做的任何操作的结果都是非必败态

知道了这个还是不管用,最关键还得找出必败态,这个题的必败态是a1^a2^....^an=0,证明有三:

首先看是否满足必败态条件一:当每堆的石子数都为0时,自然抑或结果也为0,满足

然后看是否满足必败态条件二:当a1^a2^....^an=k(k不等于0),则一定存在某个ai,它的二进制表示在k的最高位上是1(否则k的最高位那个1是怎么得到的)。然后a1^a2^...^ai'.^an=0,此时这个ai'=ai^k,也就是a1^a2^...^ai^...^an^k=0,并且这个ai^k<ai,这个条件是肯定的,然后也就满足条件二了。

最后看是否满足必败态条件三:当a1^a2^....^an=0时,肯定不存在操作使得a1^a2^..ai'..^an=0,可以反证下,如果a1^a2^..^ai'..^an=0,那么a1^a2^....^an=a1^a2^..^ai'..^an,然后异或操作满足消去率,把其他的消去后,也就是ai=ai',这也就是说一个都不拿么,与题意正好相反,所以在必败态下做的任何操作的结果都是非必败态。

参考了一个写的很好的解释

附上代码:


#include<iostream>
#include<cstdio>

using namespace std;

int m,a;

int main()
{
    while(scanf("%d",&m)!=EOF){
        int ans=0;
        while(m--){
            scanf("%d",&a);
            ans^=a;
        }
        printf("%s\n",ans==0?"No":"Yes");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/87003312