Description
小約翰經常和他的哥哥玩一個非常有趣的遊戲:桌子上有n堆石子,小約翰和他的哥哥輪流取石子,每個人取的時候,可以隨意選擇一堆石子,在這堆石子中取走任意多的石子,但不能一粒石子也不取,我們規定取到最後一粒石子的人算輸。小約翰相當固執,他堅持認爲先取的人有很大的優勢,所以他總是先取石子,而他的哥哥就聰明多了,他從來沒有在遊戲中犯過錯誤。小約翰一怒之前請你來做他的參謀。自然,你應該先寫一個程序,預測一下誰將獲得遊戲的勝利。
Input
本題的輸入由多組數據組成,第一行包括一個整數T,表示輸入總共有T組數據(T≤500)。每組數據的第一行包括一個整數N(N≤50),表示共有N堆石子,接下來有N個不超過5000的整數,分別表示每堆石子的數目。
Output
每組數據的輸出佔一行,每行輸出一個單詞。如果約翰能贏得比賽,則輸出“John”,否則輸出“Brother”,請注意單詞的大小寫。
Sample Input
3
3 5 1
1
1
Sample Output
Brother
HINT
【數據規模】
對於40%的數據,T ≤ 250。
對於100%的數據,T ≤ 500。
Source
這題一看就是博弈論。題面太明顯。。
那麼怎麼做呢?我們可以發現這道題就是經典Nim取石子游戲的簡單變形,就是取到最後一個輸。
首先我們分析一下問題可以發現:
1、如果一堆數目爲1 必敗; 否則必勝。
2、如果堆數爲2 兩堆相同且不爲一,必敗;否則必勝。
3、就是要拿完後讓兩堆相同且不爲一。
那麼這就是sg函數了。每一堆的sg值是它堆本身的數量。把全是一的情況分開討論,剩下求sg值就可以了。
#include <bits/stdc++.h>
using namespace std;
int n,T;
int a[55];
int main()
{
scanf("%d",&T);
while (T --)
{
scanf("%d",&n);
int ans = 0;
for(int i = 1; i <= n; i ++)
scanf("%d",&a[i]);
for(int i = 1; i <= n; i ++)
if (a[i]!=1) {ans= -1; break;}
if (ans == 0)
{
if (n % 2 == 1) printf("Brother\n");
else printf("John\n");
continue;
}
else
{
ans = 0;
for (int i = 1; i <= n; i ++) ans ^= a[i];
if (ans != 0) printf("John\n");
else printf("Brother\n");
continue;
}
}
return 0;
}