【参考】http://book.2cto.com/201210/5663.html
【参考】http://www.cnblogs.com/exponent/articles/2141477.html
nim game定义:
Nim是一种两个人玩的游戏,玩家双方面对一堆硬币(或者石头或者豆粒)。假设有k≥1堆硬币,每堆分别有n1,n2,…,nk枚硬币。这一游戏的目标就是取得最后一枚硬币。游戏的规则如下:
(1)玩家轮番出场(我们称第一个取子的玩家为Ⅰ,而第二个玩家为Ⅱ)。
(2)当轮到一个玩家取子时,他们都要从选择的硬币堆中至少取走一枚硬币。(这位玩家也可以把所选硬币堆的硬币都取走,于是剩下一个空堆,这时它“退出”。)
当所有硬币堆都空了的时候,游戏结束。走最后一步的玩家,即取走最后一枚硬币的玩家获胜。
在这个游戏中的变量是堆数k和堆中的硬币数n1,n2,…,nk。我们要问的组合问题是确定是第一个玩家胜还是第二个玩家胜1,以及这位玩家为了获胜应该如何取子,也就是获胜策略。
为了进一步理解Nim游戏,下面我们考虑一些特殊的情况2。如果一开始就只有一堆硬币。那么玩家Ⅰ取走所有硬币就可以获胜。现在假设k=2,且分别有n1枚和n2枚硬币。玩家Ⅰ是否可以获胜不取决于n1,n2具体是多少,而是取决于它们是否相等。假设n1≠n2。玩家Ⅰ可以从大堆中取走足够多的硬币以便对于玩家Ⅱ来说,剩余两堆的大小相同。现在,当轮到玩家Ⅰ时,他可以模仿玩家Ⅱ的取子方式。因此,如果玩家Ⅱ从一堆中取走了c枚,那么玩家Ⅰ则从另一堆中取走相同数目的硬币。这样的策略保证玩家Ⅰ可以获胜。如果n1=n2,那么玩家Ⅱ通过模仿玩家Ⅰ的取子方式而获胜。因此,我们就完全解决了2堆的Nim游戏的取子问题。下面是2堆Nim游戏的一个例子,其堆的大小分别是8和5:
上述解决2堆Nim游戏的想法是用某种方式取子使得剩余两堆的大小相同,这一想法可以推广到任意k堆的情况。
把nim每堆的数字用二进制表示,然后位数对齐进行异或运算,如果全0则说明是game是平衡的,否则是非平衡的。
若一个Nim游戏不是平衡的,则称它为非平衡的(unbalanced)。我们说第i位是平衡的,指的是和ai+bi+…+ei是偶数,否则就是非平衡的。因此,若一个游戏是平衡的,则它在各个位上都是平衡的,而对于非平衡游戏来说,至少存在一个非平衡位。
于是我们有下面的陈述:
玩家Ⅰ(先出手的)能够在非平衡Nim游戏中获胜,而玩家Ⅱ(后出手的)则能够在平衡Nim游戏中获胜。
为了理解上述的结论,我们扩展2堆Nim游戏中使用的策略。假设这个Nim游戏是非平衡的。设最大不平衡位是第j位。于是,玩家Ⅰ以某种方式取走硬币给玩家Ⅱ留下一个平衡游戏。他的作法是:选出一个第j位上是1的堆,并从中取走一定数目的硬币使得剩下的游戏是平衡的(参见练习题32)。无论玩家Ⅱ怎样做,他都不得不又给玩家Ⅰ留下一个不平衡的游戏,玩家Ⅰ又把这个游戏变成平衡游戏。如此这般继续下去就可以保证玩家Ⅰ获胜。如果这个游戏开始时就是平衡游戏,那么玩家Ⅰ第一次取子使其变成不平衡游戏,此时轮到玩家Ⅱ采用平衡游戏的策略。
23 = 8 |
22 = 4 |
21 = 2 |
20 = 1 |
|
大小为7的堆
|
0
|
1
|
1
|
1
|
大小为9的堆
|
1
|
0
|
0
|
1
|
大小为12的堆
|
1
|
1
|
0
|
0
|
大小为15的堆
|
1
|
1
|
1
|
1
|
23 = 8 |
22 = 4 |
21 = 2 |
20 = 1 |
|
大小为7的堆
|
0
|
1
|
1
|
1
|
大小为9的堆
|
1
|
0
|
0
|
1
|
大小为12的堆
|
0
|
0
|
0
|
1
|
大小为15的堆
|
1
|
1
|
1
|
1
|
归根结底,Nim取子游戏的关键在于游戏开始时游戏处于何种状态(平衡或非平衡)和第一个游戏人是否能够按照取子游戏的获胜策略来进行游戏。
leetcode上的nim游戏是只有一堆硬币,并且每次取硬币的个数(小于等于3个,至少1个)有限制的特殊情况,
public boolean canWinNim(int n) { if (n <= 0) {return false;} return n % 4 != 0; }
原文:http://www.cnblogs.com/lucky-star-star/p/4951478.html