题目:Nim游戏
此题AC代码:
import java.util.Scanner;
class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
int n=in.nextInt();
int ans=0;
for(int i=0;i<n;i++){
ans^=in.nextInt();
}
if(ans==0){
System.out.println("No");
}else{
System.out.println("Yes");
}
}
}
1.结论:
一共有n堆石子,各堆石子数目分别是:a1 a2 a3 ... an
如果a1 ^ a2 ^ a3 ^ ... ^an = 0,则先手必败;
如果a1 ^ a2 ^ a3 ^ ... ^an ≠ 0,则先手必胜。
2.首先来证明以下结论:
1.0 ^ 0 ^ 0 ^... ^ 0 =0。
说明:结果各个堆的石子数目都是0,即没有石子可以拿,则必败。
2.a1 ^ a2 ^ a3 ^ ... ^ an=x(≠0)时,一定可以从其中一个堆中拿出几个石子从而达到a1 ^ a2 ^ a3 ^ ... ^ an=0的状态。
说明:各个堆的石子数目异或起来结果不是0,一定可以通过拿石子使异或的结果变成是0的局面。
即:当前局面必胜,可以通过拿石子转成必败局面,并将此必败局面留给对方。
3.a1 ^ a2 ^ a3 ^ ... ^ an=0时,无论怎么拿,拿之后的a1 ^ a2 ^ a3 ^ ... ^ an的结果一定不为0。
说明:各个堆的石子数目异或起来结果是0,不管怎么拿石子,异或的结果都不会是0。
即:当前的局面必败,一定不可以转成必败的局面,即留给后手的局面是必胜的,则自己必败。
3.证明过程:
证明第2点:a1 ^ a2 ^ a3 ^ ... ^ an=x(≠0)时,一定可以从其中一个堆中拿出几个石子从而达到a1 ^ a2 ^ a3 ^ ... ^ an=0的状态。
假设x的二进制表示中最高一位1在第k位,则a1~an中必然存在一个数ai的第k为是1(因为所有数的第n位都是0的话,异或的结果第k位不会是1)。
得到 :ai ^ x < ai(左右两个数的前k位一样,左边的数的第k位经过异或变成了0,所以左边的数小于右边的数)
所以:ai - (ai ^ x) >0 成立
从石子数目是ai的堆里拿出ai - (ai ^ x),即第ai堆的数目变成了ai-[ai - (ai ^ x)]=ai ^ x
则拿完后,有:a1 ^ a2 ^ ... ^ ai ^ x ^ ... ^an=(a1 ^ a2 ^ ... ^an) ^ x =x ^ x=0
得证。
证明第3点:a1 ^ a2 ^ a3 ^ ... ^ an=0时,无论怎么拿,拿之后的a1 ^ a2 ^ a3 ^ ... ^ an的结果一定不为0。
反证法:
假设从任意一堆石子数目是ai的堆中拿出若干石子后数目变成了ai ’
则:a1 ^ a2 ^ ... ^ ai ’ ^ ... ^an=0
原来:a1 ^ a2 ^ ... ^ ai ^ ... ^an=0
上下异或:ai ^ ai ’ = 0 ^ 0
得到:ai = ai ’
假设不成立。
得证。
4.总结:
若此时拿到的状态是异或为非0,由第二点得,可以将这个状态转换成异或为0的状态抛给后手,后手必败,则自己必胜。
若此时拿到的状态是异或为0,由第三点得,无论如何都不能将此状态转换成异或结果是0的状态,即后手必胜,则自己必败。