今天算法课要做一道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
我们证明当 a1a2a3…… != 0 时,可以通过从一个堆中拿金牌,使a1a2a3…… = 0
若 a1a2a3…… = x != 0,那设x的二进制表示中,1的最高位为第k位,那么,a1~an中存在至少一个数如ai它的第k位是1,所以,ai^x <ai,所以我们可以拿走一些个石子,使ai 变成 ai ^x ,这时候,a1a2a3…… 变成了 a1a2a3……aix……an = x ^ x = 0
若刚开始的时候,a1^a2…… != 0 ,那么先手的人,就可以拿走石子让a1a2a3…… = 0,然后下一个人不管怎么拿,都不为0,这样一直拿下去,先手拿到最后,a1~an 都为0,先手获胜.