有100个糖,两个人,两人每次拿 1 - 8 颗糖装进袋子里,两个人轮流拿,如何保证你拿到第100颗糖?
本题可采取逆推法,有点博弈论的意思(简单的尼姆博弈)~~
首先将一次可以取最多的糖(8)和最少的糖(1)的数量加起来(为 9 )
用 100 对 9 进行取模有两种情况:
取模为 0 ,这种情况下要后取取模为 1 ~ 8 , 这种情况先手取模的大小此时剩下糖果的数量为 9 的倍数,此时无论另外的人怎么取,现在你只需要取于9的差值。
此时就能保证我取到的是最后一颗糖果~~
有若干堆糖果,每堆糖果的数量是有限的,二个人依次从这些糖果堆中拿取任意颗糖果,至少一个(不能不取),最后一个拿光糖果的人胜利。
我们首先以一堆为例: 假设现在只有一堆糖果,你的最佳选择是将所有糖果全部拿走,那么你就赢了。
如果是两堆:假设现在有两堆糖果且数量不相同,那么你的最佳选择是取走多的那堆糖果中多出来的那几个,使得两堆糖果数量相同,这样,不管另一个怎么取,你都可以在另一堆中和他取相同的个数,这样的局面你就是必胜。比如有两堆石子,第一堆有3个,第二堆有5个,这时候你要拿走第二堆的三个,然后两堆就都变成了3个,这时你的对手无论怎么操作,你都可以“学”他,比如他在第一堆拿走两个,你就在第二堆拿走两个,这样你就是稳赢的
如果是三堆 ,我们用(a,b,c)表示某种局势:
首 先(0,0,0)显然是奇异局势,无论谁面对奇异局势,都必然失败;第二种奇异局势是 (0,n,n),只要与对手拿走一样多的物品,最后都将导致(0,0,0);仔细分析一 下,(1,2,3)也是奇异局势,无论对手如何拿,接下来都可以变为(0,n,n)的情型。从中我们要明白两个理论:
一个状态是必败状态当且仅当它的所有后继都是必胜状态一个状态是必胜状态当且仅当它至少有一个后继是必败状态有了这两个规则,就可以用递推的方法判断整个状态图的每一个结点都是必胜还是必败状态。
这里引入L . Bouton在1902年给出的定理:状态(x1,x2,x3)为必败状态当且仅当x1 XOR x2 XOR x3=0,这里的XOR是二进制的逐位异或操作,也成Nim和。
也就是当Nim和 != 0时,先手胜利,否则失败
计算机算法里面有一种叫做按位模2加,也叫做异或的运算,我们用符号(+)表示这种运算。这种运算和一般加法不同的一点是1+1=0。先看(1,2,3)的按位模2加的结果:
1 = 二进制 01 2 = 二进制 10 3 = 二进制 11 (+) —————————————— 0 = 二进制 00 (注意不进位)对于奇异局势(0,n,n)也一样,结果也是0。
任何奇异局势(a,b,c)都有 a ⊕ b ⊕ c = 0 a\oplus b\oplus c =0 a⊕b⊕c=0 。 — 此处 ⊕ 等效于 ^
如果我们面对的是一个非奇异局势(a,b,c),要如何变为奇异局势呢?假设 a < b< c,我们只要将 c 变为 a ⊕ b a \oplus b a⊕b 即可,因为有如下的运算结果:
a ⊕ b ⊕ ( a ⊕ b ) = ( a ⊕ a ) ⊕ ( b ⊕ b ) = 0 ⊕ 0 = 0 a\oplus b\oplus (a\oplus b) = (a\oplus a)\oplus (b\oplus b) = 0 \oplus 0 = 0 a⊕b⊕(a⊕b)=(a⊕a)⊕(b⊕b)=0⊕0=0
要将c 变为 a ⊕ b a \oplus b a⊕b ,只要从 c 中减去 c − ( a ⊕ b ) c-(a \oplus b) c−(a⊕b)即可。也就是取走 a ⊕ b a \oplus b a⊕b 颗糖果。这里我们要了解异或运算的一个特点 a ⊕ c ⊕ c = a a \oplus c\oplus c = a a⊕c⊕c=a
14(+)21=27,39-27=12,所以从39中拿走12个物体即可达到奇异局势(14,21,27)。
(55,81,121)55(+)81=102,121-102=19,所以从121中拿走19个物品就形成了奇异局势(55,81,102)。
(29,45,58)29(+)45=48,58-48=10,从58中拿走10个,变为(29,45,48)。
我们来实际进行一盘比赛看看: 甲:(7,8,9)->(1,8,9)奇异局势乙:(1,8,9)->(1,8,4)甲:(1,8,4)->(1,5,4)奇异局势乙:(1,5,4)->(1,4,4)甲:(1,4,4)->(0,4,4)奇异局势乙:(0,4,4)->(0,4,2)甲:(0.4,2)->(0,2,2)奇异局势乙:(0,2,2)->(0,2,1)甲:(0,2,1)->(0,1,1)奇异局势乙:(0,1,1)->(0,1,0)甲:(0,1,0)->(0,0,0)奇异局势甲胜。
第一个类型: 就是让其判断胜利的人,对n堆石子求异或和,根据当Nim和 != 0时,先手胜利,否则失败就能判断出来。
第二个类型: 先取完者判赢,统计一下所有数字大于1的个数,并将所有数字异或一遍。若大于1的个数为0&&异或和为0||大于1的个数大于0&&异或和不为零,则先手胜,否则后手胜。
第三个类型: 限制最多取的个数,例如第i堆石子共有m个,最多取r个,先对m=m%(r+1);然后在进行异或求和。再根据异或和判断输赢。
第四种类型: 先手的人想赢,第一步有多少种选择。当先手必输时,很显然是0。如果先手赢,那么先手必须努力创造奇异局势,即让其剩余的石子量异或和为0,上面已经讲了当面对非奇异局势是如何转化成奇异局势。当Nim游戏的某个位置:(x1,x2,x3),当且仅当其各部分的nim - sum = 0(即 x 1 ⊕ x 2 ⊕ x 3 = 0 x1\oplus x2\oplus x3 = 0 x1⊕x2⊕x3=0(也就是各部分的异或为0)) 当前位置为必败点,这对于多个堆的情况同样适用。 我们首先求出所有堆异或后的值sum,再用这个值去对每一个堆进行异或,令 r e s = x 1 ⊕ s u m res = x1\oplus sum res=x1⊕sum (sum为所有堆的异或和)。
如果res < x1的话,当前玩家就从x1中取走(x1-res)个,使x1乘下res这样必然导致所有的堆的异或值为0,也就是必败点(达到奇异局势)这就是一种方案。遍历每一个堆,进行上面的断判就可以得到总的方案数。
解析:
r e s = x 1 ⊕ s u m res = x1\oplus sum res=x1⊕sum 其实就是除了x1之外的n-1堆异或和a ⊕ b ⊕ c = s u m ; s u m ⊕ c = a ⊕ b ⊕ c ⊕ c = a ⊕ b a\oplus b\oplus c=sum;sum\oplus c=a\oplus b\oplus c\oplus c=a\oplus b a⊕b⊕c=sum;sum⊕c=a⊕b⊕c⊕c=a⊕b
注意一个必败点不可能导致另一个必败点,因为如果这样的话当前这个必败点就不是必败点了,所以这里对于每个堆的操作至多只有一种方法
如果res > x1的话就无论从这个堆取走多少都不可能导致必败点!!!
如有不同见解,欢迎留言讨论~~~