异或运算的应用与nimm博弈

异或运算的性质
1、交换律
2、结合律(即(a^b)^c == a^(b^c))
3、对于任何数x,都有x^x=0,x^0=x
4、自反性 A XOR B XOR B = A xor 0 = A
5、消去率 a^b=c^b;则一定有a=c ,这一条是and or都不能满足的,只有+ -才会有的
应用1:所有的程序教科书都会向初学者指出,要交换两个变量的值,必须要引入一个中间变量。但如果使用异或,就可以节约一个变量的存储空间: 设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值 表达式 (值) :
A=A^B
B=B^A
A=A^B
类似地,该运算还可以应用在加密,数据传输,校验等等许多领域。
应用2:
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现
一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空
间,能否设计一个算法实现?

解法一、显然已经有人提出了一个比较精彩的解法,将所有数加起来,减去1+2+…+1000的和。
这个算法已经足够完美了,相信出题者的标准答案也就是这个算法,唯一的问题是,如果数列过大,则可能会导致溢出。
解法二、异或就没有这个问题,并且性能更好。
将所有的数全部异或,得到的结果与1^2^3^…^1000的结果进行异或,得到的结果就是重复数。

但是这个算法虽然很简单,但证明起来并不是一件容易的事情。这与异或运算的几个特性有关系。
首先是异或运算满足交换律、结合律。
所以,1^2^…^n^…^n^…^1000,无论这两个n出现在什么位置,都可以转换成为1^2^…^1000^(n^n)的形式。

其次,对于任何数x,都有x^x=0,x^0=x。
所以1^2^…^n^…^n^…^1000 = 1^2^…^1000^(n^n)= 1^2^…^1000^0 = 1^2^…^1000(即序列中除了n的所有数的异或)。

令,1^2^…^1000(序列中不包含n)的结果为T
则1^2^…^1000(序列中包含n)的结果就是T^n。
T^(T^n)=n。
所以,将所有的数全部异或,得到的结果与1^2^3^…^1000的结果进行异或,得到的结果就是重复数。
当然有人会说,1+2+…+1000的结果有高斯定律可以快速计算,但实际上1^2^…^1000的结果也是有规律的,算法比高斯定律还该简单的多。

应用3:
google面试题的变形:一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?
解法有很多,但是最好的和上面一样,就是把所有数异或,最后结构就是要找的,原理同上!

尼姆博弈(nimm’s game):
有若干堆石子,每堆石子的数量都是有限的,合法的移动是“选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了,则判负(因为他此刻没有任何合法的移动)。
求必胜策略。
结论:为了方便讨论,我们假设有3堆石子(a,b,c),定义a^b^c=0的情况为奇异状态,无论谁开始移动的时候面对的是奇异状态,都是必输。
方法:当我们面对非奇异状态的时候,移动x个石子,使下个人移动的时候变为奇异状态
非奇异局势(a,b,c),d=(a(^)b(^)c),a,b,c中存在一个数,^d小于自身,假设这个数是c。要如何变为奇异局势呢?我们只要将 c 变为 a^b,即可,因为有如下的运算结果:
a^b^(a^b)=0;
而要将c 变为a^b,只要从 c中减去 c-a^b即可(c一定大于a^b),所以我们在面对非奇异状态的时候只需从最多的那一堆c中移动x=(c-a^b)个石子,使c变成a^b即可把状态变为奇异状态,保证必胜!
推广到i个的情况,也就是存在一个ai,让ai变为ai’即可把非奇异状态变为奇异状态。其中ai’为除去ai外所有石子数的异或:(a1^a2^a3…^an)

你可能感兴趣的:(算法)