尼姆博弈
尼姆博弈
题目描述
母题:有若干堆石子,每堆石子的数量是有限的,二个人依次从这些石子堆中拿取任意的石子,至少一个(不能不取),最后一个拿光石子的人胜利。
输入示例
输入: (1,8,9)
输出: false
解释: 这是奇异局势,所以先手输了。
解题思路
- 假设现在只有一堆石子,你的最佳选择是将所有石子全部拿走,那么你就赢了。
- 假设现在有两堆石子且数量不相同,那么你的最佳选择是取走多的那堆石子中多出来的那几个,使得两堆石子数量相同,这样,不管另一个怎么取,你都可以在另一堆中和他取相同的个数,这样的局面你就是必胜。
- 假设现在有三堆石子 ,我们用(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"); //先手必胜
}

浙公网安备 33010602011771号