题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1022
思路
一般的nim取石子都是最先取不到石子的人输,而这题恰好相反:最后取石子的人输。
显然每个游戏者都会想方设法只留1个石子给对手最后取。因此可以总结最后成为必败态的局面的情况:只有1个石子。
那么我们在分析这个博弈游戏时,就要考虑两个问题:1、当前局面是否是单一游戏(只剩下一堆石子) 2、每个堆是否只有1个石子。
于是可以组合出下面四种情况进行讨论(设当前局面SG函数为 SG )
A、当前局面只剩下一堆石子,并且只剩下一个石子了 显然是必败态
B、当前局面有多堆石子,每个堆只有1个石子。显然此时若堆的个数为奇数则后手必胜,偶数则先手必胜。
C、当前局面只剩下一堆石子,这个堆有多个石子。显然先手胜
D、当前局面有多堆石子,存在有多个石子的堆。
首先考虑特殊情况A、B,可以总结为:所有石子堆的石子个数均为1,显然此时若堆的个数为奇数则后手必胜,偶数则先手必胜。(不存在子游戏 SG′>1 , SG=0 则先手胜, SG!=0 则后手胜)
然后考虑C与一般情况D:有些石子堆的石子个数大于1,此时若所有堆的SG值的亦或和为0,则后手胜,否则先手胜。
(存在子游戏
SG′>1
,
SG=0
则后手胜,
SG!=0
则先手胜)
证明:假设当前只有一个石子堆的石子个数大于1,此时所有堆的SG值的亦或和为1,先手可以通过一次操作将这个唯一的石子个数大于1的堆的二进制表示变成奇数个1;假设当前有多个石子堆的石子个数大于1,此时所有堆的SG值的亦或和为1,先手可以通过一次操作将 SG 变为0,并有子游戏 SG′>1 。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXN 1000
using namespace std;
int main()
{
int T,n;
scanf("%d",&T);
while(T--)
{
int xorsum=0;
bool flag=false;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x>1) flag=true;
xorsum^=x;
}
if(!flag)
{
if(n%2==1)
printf("Brother\n");
else
printf("John\n");
}
else
{
if(xorsum)
printf("John\n");
else
printf("Brother\n");
}
}
return 0;
}