异或法求两个人取石子的必胜策略-应聘常考的笔试算法题
问题举例:
有三堆火柴,分别有3、5、7根火柴。有两个人,轮流从这三堆里面拿火柴。每次只能从一个堆里面拿,并且要求至少拿一根,最多拿当前堆的剩余的根数。
拿走最后一根火柴的人为失败者。
编程计算出先拿的人还是后拿的人肯定会胜利,具体拿的方案是什么?
不妨先思考一会……
解法:
任意N堆,假设有A1,A2,A3,A4....An个火柴
设T=A1 xor A2 xor ... xor An(所有的异或) Ti=T xor Ai(除i外所有的异或)
1.如果T=0 先取的人必然输
2.如果T>0 先取的人必然赢
他只要每次取的时候保持T=0就可以了
while(还有火柴)
{
a.在N堆中找第一个i,使得Ai>Ti(可以证明T>0时候必然存在这样的i)
b.然后从Ai中取走Ai-Ti个
c.那么T=Ti xor (Ai-(Ai-Ti))=Ti xor Ti=0
}
原理解析:
1. 首先给出下面会用到的几条异或的性质
性质1:异或满足交换律,结合律
性质2:如果a<2^t 那么有a xor 2^t=a+2^t,如果a的最高非零位为i,那么a xor 2^i =a-2^i
性质3:如果a<2^t b<2^t 那么(a xor b)+2^t=a xor (b+2^t)
证明:a<2^t b<2^t 则a xor b<2^
由性质2有 (a xor b)+2^t=a xor b xor 2^t=a xor (b+2^t)
性质4:对任意a,偶数个a异或结果为0,奇数个a异或结果为a
--------------------------------------------------------------------------------
2.对一个非负整数序列定义平衡态和非平衡态
对n个非负整数序列A1,A2,...An
令T=A1 xor A2 xor ... xor An
Ti=T xor Ai
定义平衡态为T=0 非平衡态为T>0
--------------------------------------------------------------------------------
3.证明必然存在从非平衡态到平衡态的转化
假设现在有T>0 我们证明必然存在t使得At>Tt
设A1 A2 ... An对应的二进制数中,最大数的最高非零位为i 并且设有m个数的最高非零位也是i
(1)当m为奇数
设At是其中的一个数,At>=2^i
那么剩下的数字有m-1个大于2^i的数字 因为m-1为偶数 所以这m-1个数字异或的值<2^i
其他n-m个小于2^i的数字异或的值<2^i
所以Tt=T xor At<2^i
所以At>Tt
(2)当m为偶数
不失一般性,假设A1 ... Am为这样的数字
T=A1 xor A2 xor ... xor Am xor ...xor An
=(A1 xor 2^i) xor (A2 xor 2^i) xor ... xor (Am xor 2^i) ... xor An
=B1 xor B2 xor ... xor Bm xor Am+1 xor ... xor An
其中Bt=At-2^i t=1,2,...,m
如果序列B1 B2...An 满足(1)那么问题得解
否则继续做(2)的操作 直到满足(1)为止
我们选取此时序列为C1 xor C2 xor ... xor C? xor ... xor An
那么C1是A1与一系列的2^i异或后得到的
也就是说A1=C1+2^i1+2^i2+2^ix i1>i2>...>ix
因为C1>T xor C1 所以T xor C1<2^ix
那么C1+2^i1+2^i2+...+2^ix>(T xor C1)+2^i1+2^i2+...+2^ix=T xor A1
则A1>T xor A1=Ti
现在我们只要从At中取走At-Tt就能保证T=0
T=Tt xor (At-(At-Tt))=Tt xor Tt=0
问题得证
--------------------------------------------------------------------------------
4.证明必然存在从平衡态到非平衡态的转化
对任意一个At 从中拿走任意x 0<x<At
因为T=Tt xor At=0 所以Tt=At
现在拿走x后 必然有Tt!=At
也就是T!=0
问题得证
--------------------------------------------------------------------------------
5.取石子问题
在上面的证明中,我已经证明了必然存在从平衡态到非平衡态的转化
下面我们看看这样的结论在经典的取石子问题中的应用
( 取 石 子 游 戏 1) 任给N堆石子,两人轮流从任一堆中任取(每次只能取自一堆),取最后一颗石子的人获胜,问先取的人如何获胜?
根据上面所述,如果开始的时候T=0,那么没有获胜的可能,如果开始的时候T>0,那么只要每次取出石子使得T=0即可
( 取 石 子 游 戏 2) 任给N堆石子,两人轮流从任一堆中任取(每次只能取自一堆),规定每方每次最多取K颗,取最后一颗石子的一方获胜.问先取的人如何获胜?
与上面的问题比,这个更复杂一些,我们可以这样做
令Bi=Ai mod(K+1)
定义T‘=B1 xor B2 xor ... xor Bn
如果T‘=0 那么没有获胜可能
如果T’>0 那么必然存在取的方法,使得T‘=0
假设对方取了在Ai中取了r<=K个
如果Ai中剩下的石子多于K 那么就在Ai中取走K+1-r个 则Bi不变 T‘还是0
如果Ai<=K 那么我们需要重新计算Bi和T‘ 按照上面的方法来做就可以了
posted on 2009-10-24 01:08 CLive Studio 阅读(1298) 评论(1) 编辑 收藏 举报