由黑球白球问题相到的
一个袋子里有100个黑球和100个白球,每次从袋子里面取出两个球扔掉,
规则如下:如果取出的两个球颜色相同则放入袋中一个黑球,不同则放入一个白球。
例如:从袋子中取出一白一黑两个球,那么则将这两个球扔掉,然后重新放回袋子中一个白球。如果取出两个白球,则放回一个黑球。
问题:最后剩余的一个球的颜色是黑色还是白色?
出自《编程之美》
思路:
1.问题抽象:
相同为黑,不同为白,您能想到某种计算机位操作吗?
异或,好吧,我没有想到。设白球为1,黑球为0,那么取球的规则就被简化为对100个0和100个1做无序的异或操作。
假如您只知道异或操作的性质想必您一定知道了答案。
不知道也没有关系
2.问题归纳简化
1)假设袋子中只有一白一黑两个球:那么1^0=1 , 即剩下一个白球
2)假设有两个白球两个黑球:1^0^1^0=0 , 0^0^1^1=0, ...,发现怎样组合都可以,你是不是想起异或操作是否满足交换律与结合率,赶紧在纸上画画,发现果然如此。
...
如果操作满足结合率和交换律,那么说明这些100个0和100个1做异或操作的顺序无论如何变都一样。
下面有两种思路,
逆向:既然可以随意组合,那么组合成这样:(0^0^...^0)[100]^(1^1^...^1)[100],很容易看出,前面括号里的一大堆0做异或操作都是0。后面的一堆1可能比较棘手。好吧,继续归纳简化:
1^1=0,
1^1^1=1,
1^1^1^1=0
...难道与奇偶有关系?奇数个1做异或都为1,偶数个则为0,能用归纳法给出证明吗?很简单,不说了
我们的问题从(0^0^...^0)[100]^(1^1^...^1)[100] 简化为 0^0=0.
好吧,给出结论:无论您手多高多牛,最后剩下的一定是“0”代表的黑球。
异或的还有一个用途:不用中间值的交换a和b的算法
void swap(int& a , int& b)
{
a=a^b;
b=a^b;
a=a^b;
}
它利用了异或操作的一个性质:
a^b^b=a
a^b^a=b