首页 > 其他 > 详细

leetcode day2

时间:2015-11-09 23:56:24      阅读:473      评论:0      收藏:0      [点我收藏+]

【参考】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)。无论玩家Ⅱ怎样做,他都不得不又给玩家Ⅰ留下一个不平衡的游戏,玩家Ⅰ又把这个游戏变成平衡游戏。如此这般继续下去就可以保证玩家Ⅰ获胜。如果这个游戏开始时就是平衡游戏,那么玩家Ⅰ第一次取子使其变成不平衡游戏,此时轮到玩家Ⅱ采用平衡游戏的策略。

 

下面应用此获胜策略来考虑4-堆的Nim取子游戏。其中各堆的大小分别为7,9,12,15枚硬币。用二进制表示各数分别为:0111,1001,1100和1111。于是可得到如下一表:
 

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
由Nim取子游戏的平衡条件可知,此游戏是一个非平衡状态的取子游戏,因此,游戏人I在按获胜策略进行取子游戏下将一定能够取得最终的胜利。具体做法有多种,游戏人I可以从大小为12的堆中取走11枚硬币,使得游戏达到平衡(如下表),
 

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
之后,无论游戏人II如何取子,游戏人I在取子后仍使得游戏达到平衡。
同样的道理,游戏人I也可以选择大小为9的堆并取走5枚硬币而剩下4枚,或者,游戏人I从大小为15的堆中取走13枚而留下2枚。

归根结底,Nim取子游戏的关键在于游戏开始时游戏处于何种状态(平衡或非平衡)和第一个游戏人是否能够按照取子游戏的获胜策略来进行游戏。

 

 

leetcode上的nim游戏是只有一堆硬币,并且每次取硬币的个数(小于等于3个,至少1个)有限制的特殊情况,

public boolean canWinNim(int n) {
    if (n <= 0) {return false;}
    return n % 4 != 0;
}

 


  • According to the hint, we know that if n = 4, no matter how many stones I remove, I lose. If n = 5, I can remove one stone and there are 4 stones for another player. Thus, I win. Similarly, if n = 6 or 7, I can remove 2 or 3 stones and i win finally.
  • If n = 8, no matter how many stones I remove, there are 7 or 6 or 5 stones for another player, s/he can remove stones as we said before and then wins.
  • If n = 9 or 10 or 11, I can leave 8 stones to another player, then I win.
  • If n = 12, I can leave 9, 10 or 11 stones to another player. Then, s/he can leave 8 stones to me, then I lose. ......
  • The rule is: if (n % 4 == 0) then I lose.

 

leetcode day2

原文:http://www.cnblogs.com/lucky-star-star/p/4951478.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!