尼姆博弈
阿新 • • 發佈:2022-04-05
尼姆博弈
題目描述
母題:有若干堆石子,每堆石子的數量是有限的,二個人依次從這些石子堆中拿取任意的石子,至少一個(不能不取),最後一個拿光石子的人勝利。
輸入示例
輸入: (1,8,9)
輸出: false
解釋: 這是奇異局勢,所以先手輸了。
解題思路
- 假設現在只有一堆石子,你的最佳選擇是將所有石子全部拿走,那麼你就贏了。
- 假設現在有兩堆石子且數量不相同,那麼你的最佳選擇是取走多的那堆石子中多出來的那幾個,使得兩堆石子數量相同,這樣,不管另一個怎麼取,你都可以在另一堆中和他取相同的個數,這樣的局面你就是必勝。
- 假設現在有三堆石子 ,我們用(a,b,c)表示某種局勢,首 先(0,0,0)顯然是奇異局勢,無論誰面對奇異局勢,都必然失敗。第二種奇異局勢是 (0,n,n),只要與對手拿走一樣多的物品,與假設
(2)
注意:與威佐夫博弈區別在於該博弈只能從一堆中取。
一個狀態是必敗狀態當且僅當它的所有後繼都是必勝狀態, 稱之為利己態,用字母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"); //先手必勝
}