Nim游戏
Nim 游戏
今天算法课要做一道Nim游戏的题,内容是这样:
冰墩墩和雪融融放置了N堆不同数目的金牌,编号1..N,第i堆中有A[i]个金牌。
每一次行动,冰墩墩和雪融融(电脑)可以选择从一堆金牌中取出任意数量的金牌。至少取1个,至多取出这一堆剩下的所有金牌。
冰墩墩和雪融融轮流行动,取走最后一个金牌的人获得胜利。
假设每一轮游戏都是冰墩墩先行动,请你判断在给定的情况下,如果双方都不会失误,谁会获得胜利?
输入:
第1行:1个整数N。表示金牌堆数。1≤N≤100
第2行:N个整数,第i个整数表示第i堆金牌的个数A[i],1≤A[i]≤10000
输出:
第1行:1个整数,若冰墩墩能够获胜输出“0",否则输出“1"
想了好久没做出来,最后去ACWING看了y总的讲解才明白,这里记录一下
先上代码:
#include "iostream"
#include "vector"
#include "algorithm"
#include "set"
#include "map"
#include "stdio.h"
#include "string"
#include "string.h"
#include "cstring"
#include "utility"
#include "bitset"
#include "stack"
#include "queue"
using namespace std;
const int N = 1110;
int A[N];
int nim (int A[],int n){
int res = 0;
for(int i = 1; i <= n; i++ ) {
res ^= A[i];
}
return (res == 0);
}
int main(){
int n;
cin>>n;
for(int i = 1; i <= n; i++ ){
cin>>A[i];
}
printf("%d\n",nim(A,n));
}
再上结论:
若a1a2a3.……an = 0,则先手的必败,否则先手必胜。为什么呢?
证明过程
首先
有人拿走最后一块金牌后,每一堆的金牌数都是0,这时候a1a2a3…… = 0
然后
我们证明当 a1^ a2 ^a3…… != 0 时,可以通过从一个堆中拿金牌,使a1^ a2^a3…… = 0
若 a1^ a2^a3…… = x != 0,那设x的二进制表示中,1的最高位为第k位,那么,a1~an中存在至少一个数如ai它的第k位是1,所以,ai^x <ai,所以我们可以拿走一些个石子,使ai 变成 ai ^x ,这时候,a1a2a3…… 变成了 a1^ a2^ a3……aix……an = x ^ x = 0
再想
若刚开始的时候,a1^a2…… != 0 ,那么先手的人,就可以拿走石子让a1^ a2^a3…… = 0,然后下一个人不管怎么拿,都不为0,这样一直拿下去,先手拿到最后,a1~an 都为0,先手获胜.