尼姆博弈

尼姆博弈

题目描述

母题:有若干堆石子,每堆石子的数量是有限的,二个人依次从这些石子堆中拿取任意的石子,至少一个(不能不取),最后一个拿光石子的人胜利。

输入示例

输入: (1,8,9)
输出: false
解释: 这是奇异局势,所以先手输了。

解题思路

  1. 假设现在只有一堆石子,你的最佳选择是将所有石子全部拿走,那么你就赢了。
  2. 假设现在有两堆石子且数量不相同,那么你的最佳选择是取走多的那堆石子中多出来的那几个,使得两堆石子数量相同,这样,不管另一个怎么取,你都可以在另一堆中和他取相同的个数,这样的局面你就是必胜。
  3. 假设现在有三堆石子 ,我们用(a,b,c)表示某种局势,首 先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败。第二种奇异局势是 (0,n,n),只要与对手拿走一样多的物品,与假设(2)类似。最后都将导致(0,0,0)。仔细分析一下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情型。

注意:与威佐夫博弈区别在于该博弈只能从一堆中取。

一个状态是必败状态当且仅当它的所有后继都是必胜状态, 称之为利己态,用字母T表示。

一个状态是必胜状态当且仅当它至少有一个后继是必败状态,称之为利他态,用字母S表示。

证明

定义:状态(x1,x2,x3)为必败状态当且仅当\(x1\bigoplus x2\bigoplus x3=0\),这里的\(\bigoplus\)是二进制的逐位异或操作,也成Nim和。

定理:对于任何一个S态,总能从一堆石头中取出若干个使之成为T态。

反证法:

改变\(A[i]\)的值为\(A[i\prime ]\),即\(A[i\prime]\bigoplus A[i]\neq 0\)\(S\prime\)为利他态 。

\[S=A[1]\bigoplus A[2]\bigoplus \cdots \bigoplus A[i]\bigoplus \cdots \bigoplus A[n]=0 \tag{1} \]

\[S\prime =A[1]\bigoplus A[2]\bigoplus \cdots \bigoplus A[i\prime ]\bigoplus \cdots \bigoplus A[n]=0 \tag{2} \]

\[S\bigoplus S\prime =A[1]\bigoplus A[2]\bigoplus \cdots \bigoplus A[i]\bigoplus \cdots \bigoplus A[n] \bigoplus A[1]\bigoplus A[2]\bigoplus \cdots \bigoplus A[i\prime ]\bigoplus \cdots \bigoplus A[n]=0 \tag{3} \]

\[\Rightarrow S\bigoplus S\prime =A[i]\bigoplus A[i\prime ]=0\bigoplus 0=0 \tag{4} \]

与已知条件矛盾。

注:\(A[i]\)表示每堆石头数。

代码

public boolean helper(int[] A){
    int xor=0;
    for(int i=0;i<A.length;i++) xor^=A[i];
    if(xor!=0) return true;
    else return false;
}

拓展

尼姆博弈和巴什博弈的结合。

t堆石子,每堆石子都有n个,A和B轮流从取任意堆里取一定的石子,每次只能从一堆里至少取一个最多取m个,你先取,A取完者胜,问能否获胜?(0<=m,n<=2^31))

public void helper(int[] A,int n,int m){
    int res=0;
    for(int i=0;i<A.length;i++){
        int t=n%(m+1);    //m+1的倍数 说明先手输
        ans^=t;
    }
    if(res==0) System.out.println("B");   //后手必胜
    else System.out.println("A");         //先手必胜
}

引用

(1) 尼姆博奕(Nimm Game)_shuangde800的博客-CSDN博客

posted @ 2022-04-04 22:38  LibraXiong  阅读(162)  评论(0)    收藏  举报