关于博弈论中的Nim游戏,在蓝桥杯省赛前看了一下,很惭愧,看了半天没看很明白,就放弃了(赛前背了一个模版,幸运的是没考到)今天突然看到一道相关的题目,于是回头又看了看,可能灵感突然来了,基本看明白了,下面我就用最最最浅显的语言表达方式来对Nim游戏做一个详细的解释。
Nim游戏:有n个石堆,每堆里有数量一定的石子,两人从其中任意一堆中取任意数量的石子(不能超过这堆石子数的最大值),不能不取,最后某个人取完,所有石堆中的石子数量都为0时,另一个人就为输。
题目大致就是这样,在解这道题目前,有几个概念需要知道的:
1.异或运算符(^),异或是一种对于两个数的二进制数进行运算的逻辑运算符,同真同假为假,一真一假为真,即1^1=0,0^0=0,1^0=1。
2.定义两个状态,分别为N和P,N代表Next-position,可以理解为先手必胜状态,P代表Previous-position,可以理解为后手必胜状态(或为先手必败)。
3.N/P两个状态的关系:(1)无法进行局面转移的状态为P;
(2)只要有一种转移方式能将局面变为P,则当前状态为N;
(3)任何转移方式都只能使局面变为N,则当前状态为P。
我在这里通过Nim游戏对上面三句话做一个简单的解释:
(1)最后所有石堆中的石子都为0,此时无法再做任何操作,所以此时是P;
(2)在还剩一堆的情况下(无论个数,因为可以随意取),把这一堆都取完,留给对方 的肯定是0个石子,也就是P,所以当前肯定是N;
(3)还剩下两堆,且每堆个数为1,因为当前必须要取,而当取完后,通过(2)可知, 留给对方的局 面一定是N,所以当前肯定为P。
以上作出的解释都为特殊情况,只是方便理解。
概念就是上面几个,下面开始解Nim问题:
首先说结论:对于Nim游戏的各个石堆(a1,a2,a3......an),当且仅当a1^a2^a3^......^an=0时它为P。
看到这个结论是,确实让人感到很神奇,博弈问题竟然能和异或扯上关系,下面我对这个结论进行论证。
论证还是要根据N/P的三个状态关系来:
(1)无法移动的局面为所有石堆的石子数都为0,0^0^......^0=0,这个很简单;
(2)若当前的局面不为0,即a1^a2^a3^......^an=k,则必定有一个数ai改变ai的值为ai'(或者理解为改变当前某个石堆的状态),能使的a1^a2^a3^......^ai'^......^an=0,证明很简单,通过异或的性质,因为k的二进制最高位(从右往左)为1,可以得出一 定存在某个ai的最高位为1,此时ai'*k<ai,这个也很好理解,当前的最高位由1变为0 ,十进制时ai一定小于ai'。所以,我们可以将ai=ai'*k,此时a1^a2^a3^......^ai'*k ^.......an=0。
(3)若当前某个局面为P,即a1^a2^a3^......^an=0,一定不存在改变某 个ai,使之变为ai',a1^a2^a3^.......^ai'^......^an=0,因为异或满足消去律,消去后得ai=ai',由题目可得不能不取,即当前的ai值必须改变,所以此时ai一定不等于ai'。
理论证明就是以上这些,下面给出代码
class Main {
public static void main(String[] args) {
int x []={2,5,12,14};
f(x);
}
static void f(int x []) {
int sum=0;
for(int i=0;i<x.length;i++)
sum^=x[i];
if(sum==0)
System.out.println("必输");
for(int i=0;i<x.length;i++) {
int k=sum^x[i];
if(k<x[i])
System.out.println("原堆个数为"+x[i]+"的子堆变为"+k);//得出的结果为所有的方案第一次移动的数
}
}
}
结果如下
以上就是Nim问题的全部解题过程,如果有错误的欢迎指出,感谢!