BZOJ 1022: [SHOI2008]小约翰的游戏John【Anti-SG游戏与SJ定理】

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88636115

题目分析:

Anti-SG游戏(决策集合为空者胜)
针对这道题口胡一通。
游戏分三种情况:(下面的异或和指的是所有堆的SG值的异或和)

  • 每堆只有一个石子,此时
    • 若异或和为0(偶数堆),则先手必胜 (A)
    • 若异或和为1(奇数堆),则先手必败 (B)
  • 只有一堆石子数>1,(C)
    • 若有奇数堆石子数为1的,那么先手把当前堆取完即可,先手必胜
    • 若有偶数堆石子数为1的,那么先手把当前堆取成只剩一个石子,仍然是先手必胜
    • 注意,这时所有堆的SG值异或和一定不为0
  • 存在至少两堆石子>1
    • 异或和为0 (D)
    • 异或和不为0 (E)

根据nim游戏的原理,我们分析一下D、E状态的胜负:
首先,C状态是必胜状态,D、E状态最终都会归结到C状态。
E状态一定可以转移到D状态(因为只有一堆>1时异或和一定不为0,所以转移后仍然有至少两堆>1);
而D状态要么转移到E状态,要么转移到C状态。
所以E是必胜状态,D是必败状态。

应该解释明白了吧。。

拓展一下,就是SJ定理:

对于任意一个Anti-SG游戏,如果我们规定当局面中所有的单一游戏的SG值为0时,游戏结束,则先手必胜当且仅当:

  • 游戏中没有单一游戏的SG函数大于1 且 游戏的SG函数为0。
  • 游戏中存在某个单一游戏的SG函数大于1 且 游戏的SG函数不为0。

这道题的Code:

#include<cstdio>
#include<cctype>
#include<cstring>
#define maxn 5
inline void read(int &a){
    char c;while(!isdigit(c=getchar()));
    for(a=c-'0';isdigit(c=getchar());a=a*10+c-'0');
}
int n,x,T;
int main()
{
    read(T);
    while(T--){
        read(n);int ans=0,y=0;
        while(n--) read(x),ans^=x,y|=(x>1);
        puts((!y&&!ans)||(y&&ans)?"John":"Brother");
    }
}

猜你喜欢

转载自blog.csdn.net/C20181220_xiang_m_y/article/details/88636115