尼姆博弈(Nimm Game):
尼姆博弈指的是这样一个博弈游戏:有任意堆物品,每堆物品的个数是任意的,双方轮流从中取物品,每一次只能从一堆物品中取部分或全部物品,最少取一件,取到最后一件物品的人获胜。
结论:把每堆物品数全部异或起来,如果得到的值为0,那么先手必败,否则先手必胜。
题目:Georgia and Bob
【题意】
游戏规则如下:
1.每人每次可以且只能移动一个棋子
2.每次移动棋子的格子数不限
3.只能向左移动棋子
4.移动过程中不能覆盖或越过其它棋子
5.当谁没有棋子可以移动时,就输了
6.两人轮流移动石子,女士优先,Georigia总是先移动
7.最左端所在坐标为0,亦即放在1位置的棋子不能再往左移
假设两人一样聪明,给定棋子的初始位置,判断谁将是赢家。
【分析】
我们把棋子按位置升序排列后,从后往前把他们两两绑定成一对。如果总个数是奇数,就把最前面一个和边界(位置为0)绑定。
在同一对棋子中,如果对手移动前一个,你总能对后一个移动相同的步数,所以一对棋子的前一个和前一对棋子的后一个之间有多少个空位置对最终的结果是没有影响的。
于是我们只需要考虑同一对的两个棋子之间有多少空位。
这样一来就成了N堆取石子游戏了,这就变成了最裸的Nimm Game问题了,套用模型即可.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int N,a[1003]={},sum=0;
scanf("%d",&N);
for(int i=1;i<=N;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+N+1);
if(N%2==0){///偶数个棋子的情况
for(int k=1;k<=N;k=k+2){
sum^=(a[k+1]-a[k]-1);
}
}
else{///奇数个棋子的情况
sum=a[1]-1;
for(int k=2;k<=N;k=k+2){
sum^=(a[k+1]-a[k]-1);
}
}
if(sum)
printf("Georgia will win\n");
else
printf("Bob will win\n");
}
return 0;
}