Nim尼姆博弈
尼姆博弈(Nim Game)
一、问题模型
有 n 堆石子,每堆有若干个。两人轮流操作,每次可以从任意一堆中取走任意多枚石子(至少取 1 枚,可以取完这一堆)。
取走最后一枚石子的人获胜。问:先手是否存在必胜策略?
对应题目:洛谷 P2197 【模板】Nim 游戏
二、结论
把每一堆石子的数量全部异或起来:
- 如果异或和
!= 0,先手必胜(输出Yes) - 如果异或和
== 0,先手必败(输出No)
三、为什么是这个结论
设异或和为 S = a1 ^ a2 ^ ... ^ an。
情况一:S == 0(必败态)
无论先手从哪一堆取走多少石子,这一堆的数量都会改变,异或和就不再是 0。
也就是说,先手无论如何操作,都会把局面交给后手一个 S != 0 的局面。
情况二:S != 0(必胜态)
先手一定可以找到某一堆,取走若干石子,使新的异或和变成 0。
具体做法:设 S 的最高二进制位是第 k 位,那么一定存在某一堆 ai,它的第 k 位也是 1。把这一堆改成 ai ^ S(显然 ai ^ S < ai,相当于取走了 ai - (ai ^ S) 枚),整体异或和就变成了 0。
之后先手只需要一直模仿后手的操作,把局面重新变回 S == 0,就能保证自己取到最后一枚。
四、AC 代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while (t --)
{
int n;
cin >> n;
int res = 0;
for (int i = 0; i < n; i ++)
{
int cnt;
cin >> cnt;
res ^= cnt;
}
if (res == 0) cout << "No\n";
else cout << "Yes\n";
}
return 0;
}

浙公网安备 33010602011771号