Anti-Nim博弈原理与证明
简介
Anti-Nim博弈是Nim博弈的变形,它的定义是:
给定 \(n\) 堆物品,第 \(i\) 堆物品有 \(A_i\) 个,两人轮流取,每次可以任选一堆取走任意多个物品,可以取光但不能不取,最后把物品全部取完者失败
判断先手是否有必胜策略
推理
先手必胜当且仅当:
- 每堆的物品数都为 \(1\) 且Nim和为 \(0\)
- 有些堆的物品数大于 \(1\) 且Nim和不为 \(0\)
证明:
第一种情况:每堆物品数都为 \(1\) 且Nim和为 \(0\) ,那么 \(n\) 为偶数,易知先手必胜
第二种情况:
-
若Nim和不为 \(0\)
-
若至少还有两堆物品数大于 \(1\) ,那先手一定可以将局势变为至少有一堆物品数大于 \(1\) 且Nim和为 \(0\)
-
若只有一堆物品数大于 \(1\) ,则先手一定可以将局势变为有奇数个 \(1\)
-
-
若Nim和为 \(0\)
至少有两堆物品数大于 \(1\) ,则先手决策完之后,必定至少有一堆物品数大于 \(1\) 且Nim和不为 \(0\) ,由上段的论证我们可以发现, 此时,无论先手如何决策,都只会将游戏带入先手必胜局,所以先手必败
例题
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t, n, a, res, maxx;
scanf("%d", &t);
while(t--) {
maxx = res = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a);
res = res ^ a;
maxx = max(maxx, a);
}
if(maxx == 1)
printf("%s\n", res == 0 ? "John" : "Brother");
else
printf("%s\n", res ? "John" : "Brother");
}
return 0;
}