bzoj1022 小約翰的遊戲John

Description

小約翰經常和他的哥哥玩一個非常有趣的遊戲:桌子上有n堆石子,小約翰和他的哥哥輪流取石子,每個人取的時候,可以隨意選擇一堆石子,在這堆石子中取走任意多的石子,但不能一粒石子也不取,我們規定取到最後一粒石子的人算輸。小約翰相當固執,他堅持認爲先取的人有很大的優勢,所以他總是先取石子,而他的哥哥就聰明多了,他從來沒有在遊戲中犯過錯誤。小約翰一怒之前請你來做他的參謀。自然,你應該先寫一個程序,預測一下誰將獲得遊戲的勝利。

Input

本題的輸入由多組數據組成,第一行包括一個整數T,表示輸入總共有T組數據(T≤500)。每組數據的第一行包括一個整數N(N≤50),表示共有N堆石子,接下來有N個不超過5000的整數,分別表示每堆石子的數目。

Output

每組數據的輸出佔一行,每行輸出一個單詞。如果約翰能贏得比賽,則輸出“John”,否則輸出“Brother”,請注意單詞的大小寫。

Sample Input

2
3
3 5 1
1
1

Sample Output

John
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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章