Ration和深蓝的下午茶:取石子游戏&异或和

来源:互联网 发布:防sql注入最佳 编辑:程序博客网 时间:2024/05/11 21:33

下午茶的时候,Ration在和他的计算姬玩一个游戏:取石子游戏:有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。

玩了几局之后,深蓝一局没赢。

深蓝:哇,主人好厉害OvO!

Ration:啊哈哈哈哈,今天我来说一下这个游戏(也叫nim游戏)和异或和的关系,知道了这个,就很容易赢了。

深蓝:什么是异或和= =

Ration:(内心OS:我的AI不可能这么笨)首先得明白“异或”的概念。在C++中,"^"表示“异或”这个运算。“异或”就是说,如果两个东西一样,那么它们异或值就是0,否则就是1。这一点在二进制中体现的很明白。0^0就是0,1^1就是0,0^1就是1。举例:“a^b”就等于a,b的异或和。你是计算机,自己跑一遍就理解了。

深蓝:具体怎么操作呢?

Ration:打开编译器,使用普通OI模板。声明变量a=2,b=3。

深蓝:(机械音)声明完毕。(OS:我是计算姬,不是声控计算机!!)

Ration:输出"a^b"。

深蓝:(机械音)1。

深蓝:哦,我明白了!就是把a和b这两个十进制数字转化为对应的二进制的数字,然后按位异或(就是一位一位求异或值),然后把每一位的异或值连起来得到一个新的01数列,然后把这个数列转化为对应的十进制数,就是这两个十进制数的异或和!(qwq求夸奖)

Ration:(摸头)是这样没错。那么多个数的异或和你也会了吧?

深蓝:嗯!就是把前两个数的异或和求出来,再用前两个数的异或和与第三个数求异或和,以此类推?

Ration:是啊。

深蓝:然而这个和nim游戏有啥关系?!(qAq)

Ration:别急。当剩下的石子每一堆的数量的那些数字的异或和为0的时候,该谁取谁就gg。

深蓝:怎么证明?

Ration:首先,如果已经没有石子了,那么是不是取得那个人就gg了?

深蓝:嗯。

Ration:此时异或和为0?

深蓝:嗯。

Ration:假设现在只有两堆石子,分别有x个和y个。而且x<y。假设这时候你从第二堆中取了z(z<y)个,那么,我就有一个神秘操作:我从第一堆中取石子,让第一堆也剩下y-z个。这样,两堆总是相同的,最终你会使一堆为0,我再让另一堆为0,你就gg了。

深蓝:那么如果y-z>x呢?

Ration:那么我就取第二堆,让第二堆也只剩下X个,就可以神秘操作了。

深蓝:然而这个怎么推广到一般情况?

Ration:那我们假设现在还没拿完,还有一些石子,但是每一堆的石子数异或和为0。那很明显,你只要拿,不管拿多少,异或和不可能保持0。所以你不可能在异或和为0的情况下把它拿完。

深蓝:为什么?

Ration:比如有一堆是 ai,我们拿了x个,x<=ai,那这一堆还剩ai-x个我们把这一堆的数量变成ai-x 相当于对ai异或(ai^(ai-x))。

深蓝:笨蛋主人,说的我一脸懵!

Ration:(OS:我迟早要拆了这破机器)根据异或的自反性,a^x^x=a,那我们假设ai^k=ai-x,那么k应该是(ai^(ai-x)),再根据异或的性质 一个数只有异或自己才会等于0,因为当x>0的时候 ai-x是不可能等于ai的,所以(ai^(ai-x))不等于0,所以现在各堆石子的异或和应该是a1^a2^a3^a4^...^(ai-x)^...^an

深蓝:= =

Ration: 假设有n堆石子,第i堆被拿走了x个,ai表示第i堆的石子数,因为ai-x=ai^ai^(ai-x),所以上面那个式子就是a1^a2^...^(ai^ai^(ai-x))^..^an((ai^ai^(ai-x)):i就是被拿石子的那一堆),根据异或的结合律,上面的式子就等于(a1^a2^a3^a4^...^an)^(ai^(ai-x)),等于0^ai^(ai-x)=ai^(ai-x)。

深蓝:OvO

Ration:所以被你拿走石子后,所有石子数的异或和不可能是0,不可能一步拿光。而且,异或和不为0,一定有一种办法让异或和为0,先手必输。所以,每次异或和不为0的时候,我就让它为0,你就gg了。(小声)异或这东西应该是计算姬更厉害,然而我却用计算机中的逻辑运算打败了笨笨的计算姬啊哈哈哈哈……

深蓝:(佯怒)你说谁笨蛋!!!主人你给我回来!!!



作者水平有限,欢迎大家评论指正错误。

谢谢大家!





原创粉丝点击