一、Nim游戏介绍
给定(n)堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
据说,它源自中国,经由被贩卖到美洲的奴工们外传。辛苦的工人们,在工作闲暇之余,用石头玩游戏以排遣寂寞。后来流传到高级人士,则用便士(Pennies),在酒吧柜台上玩。
最有名的玩法,是把十二枚便士放成(3、4、5)三列,拿光铜板的人赢。
后来,大家发现,先取的人只要在(3)那列里取走(2)枚,变成了(1、4、5),就能稳操胜券了,游戏也就变得无趣了。
于是大家就增加列数,增加铜板的数量,这样就让人们有了毫无规律的感觉,不易于把握。
二、举个栗子
-
(2)和(3)两堆石子,甲先来,从(3)那堆中取(1)个,留下两堆,分别是(2)和(2)。
-
以后不管乙怎么拿,甲都和他在相反的一堆中做同样的操作,这样,肯定是乙最先面对(0),(0)状态。
三、结论
在两名选手都足够聪明,每一步都是最优解的情况下:
(a_1) ^ (a_2) ^ ... ^(a_n=0) 先手必败
(a_1) ^ (a_2) ^ ... ^(a_n
eq0) 先手必胜
就是把所有堆的石子个数异或起来,结果是零,先手必败,不是零,先手必胜。
四、扩展问题
如果(Nim)游戏中的规则稍微变动一下,每次最多只能取(K)个,怎么处理?
方法是将每堆石子数(mod (k+1)).
五、C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int main() {
//优化输入
ios::sync_with_stdio(false);
int n;
cin >> n;
int res = 0; //起始值是0,因为任何数与0进行异或都它本身
while (n--) {
int x;
cin >> x;
res ^= x;
}
if (res) puts("Yes"); //异或值是非零,则可以先手通过某种办法将异或值变为零
else puts("No"); //异或值是零,必败
return 0;
}