ProjectEuler 301 游戏中的数学

好久没做Euler题目了,上去直接挑了最后一题。一般说来越往后越难,但题目301却非常简单。更难得的是,经过一番思考,我发现自己能够比较完整的理解题目背后的数学和算法,所以把心得分享给大家。(有很多Euler题目,要么不会做,要么勉强做出结果,却想不出清晰的数学图像)

 

Nim是很经典的博弈游戏。有3堆石子,两人轮流从任一堆中取走至少1个石子,最后拿走剩下石子的人获胜。类似的游戏还有很多,比如21点:两人轮流从21个石子里拿走1~3个石子,也是最后拿走剩下石子的人获胜。有趣的是,这类游戏是存在必胜法的。

 

先看21点,要点是保持剩余石子数是4的倍数。我们记这些石子数的集合为A = {0, 4, 8, 12, 16, 20};并记第i次取石子后,剩余石子数为Ri。这些元素有3个神奇的特性:

1、游戏的最终状态0∈A,轮到谁,谁就输了。

2、如果Ri∈A,则任何取法都会使Ri+1A。例如无法直接从8到4,因为一次最多取3个石子。

3、如果RiA,则必有某种取法,使得Ri+1∈A。例如7 - 3 = 4。

由上述3个特性可知:

1、给对手剩余0则胜利,而0是4的倍数。

2、我方只要维持剩余石子数为4的倍数,则无论对手怎么取,必会偏离此状态。

3、无论对方怎么取,我方总有合适的取法,使剩余石子数回到4的倍数。

所以在对局双方都知道此必胜法的情况下,则输赢只跟谁先出手有关了。

 

有了上述例子,再看Nim游戏就比较好理解了。记第i次取石子后,三堆石子的个数分别为Xi, Yi, Zi。其必胜心法就是:从某堆中抽出适量石子,使得Xi⊕Yi⊕Zi = 0(此处及下文出现的⊕是二进制按位异或算符xor)。对比21点游戏,我们也试着"猜想"出3个神奇的特性:

1、根据规则,游戏的最终状态为Xi = Yi = Zi = 0,轮到谁,谁就输了。

2、如果Xi⊕Yi⊕Zi = 0,则任何取法都会使Xi+1⊕Yi+1⊕Zi+1≠0。

3、如果Xi⊕Yi⊕Zi≠0,则必有某种取法,使得Xi+1⊕Yi+1⊕Zi+1 = 0。

由上述3个特性可知:

1、给对手剩余Xi = Yi = Zi = 0则胜利,而此时恰好Xi⊕Yi⊕Zi = 0。

2、我方只要维持剩余石子数满足Xi⊕Yi⊕Zi = 0,则无论对手怎么取,必会偏离此状态。

3、无论对方怎么取,我方总有合适的取法,使剩余石子数回到Xi⊕Yi⊕Zi = 0的状态。

 

凑巧的是,这个猜想是成立的,但其正确性不再像21点游戏那样直观了。我给出描述性的证明,严格证明请参看Wikipedia

 

先证性质2,这个简单。由于只能从单一堆中取,且至少取走1个石子。不失一般性的,假设是从Xi中取,则必定会使Xi+1的某些二进制位发生变化,而另两堆保持不变Yi =Yi+1,Zi =Zi+1,所以Xi+1⊕Yi+1⊕Zi+1的某些位必定发生改变,而使其偏离0了。(假如游戏允许从多个堆中同时取走石子,则性质2失效。)

 

再证性质3。我们可以构造性的给出一个算法,使得在任意的Xi⊕Yi⊕Zi≠0时,总可以从某堆中取走一些的石子,使得Xi+1⊕Yi+1⊕Zi+1恢复为0。例如:

Xi = 4 = (100)2

Yi = 2 = (010)2

Zi = 3 = (011)2

-------------------

Xi⊕Yi⊕Zi = (101)2

由于Xi⊕Yi⊕Zi的最高位是第三位(bit3 = 1),则三堆中必然至少有一堆的第三位也为1,任选这样的一堆,此例即X。由于异或后的值(101)2在第一位和第三位都是1,为了让其归零,就需要让Xi+1的对应位发生变化,也就是从(100)2变为(001)2。再仔细一些,会注意到Yi、Zi的第三位要么都为0,要么都为1,则Xi+1的最高位至多是第二位,所以Xi+1i,不可能出现石子不够取的情况。综上,需要从X中拿走(100)2 - (001)2 = (011)2 = 3个石子。归纳一下,此算法为:总是从与Xi⊕Yi⊕Zi具有相同最高位的任一堆中取走石子,不失一般性的,设此堆为X。希望取走石子后此堆剩余石子Xi+1 = Xi⊕(Xi⊕Yi⊕Zi)= Yi⊕Zi,则必然可以从X中取走的数目为Xi -Xi+1的石子使得Xi⊕Yi⊕Zi = 0。

 

有了这些铺垫,题目301的解法也就很直接了。只要遍历n = [1..230],数一下满足n⊕2n⊕3n = 0的n的个数即可。(答案?保密)

 

小结一下,就会发现这类游戏的特点是对局双方仅有先后手的差别。对此有个学名:无偏博弈(Impartial game),并且所有这类游戏都等价于Nim游戏(Sprague–Grundy theorem)。他们中的每一个游戏,都拥有一个特殊的状态集合。在21点中就是集合A,在Nim中,就是那些满足X⊕Y⊕Z = 0的局面。这个集合(我称作核心集)中的状态有如下3个性质:

1、终局状态属于核心集。

2、如果当前状态属于核心集,则任意合法的动作,都会使当前状态转化到核心集之外的状态。

3、如果当前状态不属于核心集,则必存在一种精心策划的合法的动作,使当前状态转化为核心集之内的状态。

 

我还要继续深入,看看是否有更快的算法呢?让我们先瞧瞧Nim游戏的核心集的样子(图1)。咋就那么像立体的Sierpinski triangle呢?看来Nim游戏的内部隐藏了某种深层次的规律性,如果能找到,说不定会大大缩短之前遍历法的计算时间。仔细读题,初始三个堆的大小正好是n的1倍、2倍、3倍。这有什么特殊含义吗?

图1,Nim核心集,x≤y≤z。

 

晚上做梦,

1、梦见数字电路设计中讲,异或和加法是非常相似的两种运算,唯一的不同就是加法考虑进位,而异或忽略进位。

2、又梦到在二进制表示下,2n就是对n左移一位的结果。

3、当我再梦到3n = n + 2n的时候就惊醒了(晕,真的再也睡不着了)。

4、题目要找合适的n,使得n⊕2n⊕3n = 0,这不就等价于n⊕2n = n + 2n嘛。

5、不考虑进位的异或结果与考虑进位的加法结果相等,也就是说加法过程中必定不会出现进位。

6、要满足4,则n的二进制表示中的相邻位必定不能出现连续的'1',否则左移一位后必定导致加法进位,也就是n & 2n = 0。

7、至此,问题已经相当明朗,就是要在给定的范围内,构造二进制表示中没有相邻的'1'的整数n。也就是要往一串'1'中插入一些'0',并数数有多少种不同的插入方式。

 

回忆一下高考时做过的各类排列组合题吧。将n个相同的小球,全部分到m个不同的盒子里,且盒子可以空着,有多少种分法?解法为使用"第二类隔板法",将球与盒看做相同的元素,排成一串。除去左右两侧的空隙,构成n + m - 1个空隙。分成m堆则需要插入m - 1个隔板,所以有种分法。( Mathematica中对应函数为Binomial[n + m - 1, m – 1] )

 

有了这些基础,计算总数就容易多了。我们按'1'在n中出现的次数进行分类,逐个类进行计算:

 

第1类,以数(1)2为基础,插入不同个数的'0',构成新的n:

插入'0'的个数

形成n的数目

0

1

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值