[Bzoj1022][SHOI2008]小約翰的遊戲John(博弈論)
1022: [SHOI2008]小約翰的遊戲John
Time Limit: 1 Sec Memory Limit: 162 MB
Submit: 2976 Solved: 1894
[Submit][Status][Discuss]
Description
小約翰經常和他的哥哥玩一個非常有趣的遊戲:桌子上有n堆石子,小約翰和他的哥哥輪流取石子,每個人取
的時候,可以隨意選擇一堆石子,在這堆石子中取走任意多的石子,但不能一粒石子也不取,我們規定取到最後一
粒石子的人算輸。小約翰相當固執,他堅持認為先取的人有很大的優勢,所以他總是先取石子,而他的哥哥就聰明
多了,他從來沒有在遊戲中犯過錯誤。小約翰一怒之前請你來做他的參謀。自然,你應該先寫一個程序,預測一下
Input
本題的輸入由多組數據組成第一行包括一個整數T,表示輸入總共有T組數據(T≤500)。每組數據的第一行包
括一個整數N(N≤50),表示共有N堆石子,接下來有N個不超過5000的整數,分別表示每堆石子的數目。
Output
每組數據的輸出占一行,每行輸出一個單詞。如果約翰能贏得比賽,則輸出“John”,否則輸出“Brother”
,請註意單詞的大小寫。
Sample Input
2 3 3 5 1 11
Sample Output
John
Brother
分析:
好吧,我不講博弈論,講的太博大精深了。我會盡量講的通(bo)俗(da)易(jing)懂(shen),
設現在我們所有堆的石頭數量都為1。如果有奇數堆,我們是不是輸了。。。。設為情況①(必輸)
設現在我們所有堆的石頭數量都為1。如果有偶數堆,我們是不是贏了。。。。設為情況②(必贏)
(好吧上面兩個解釋太白癡了。)
設現在我們有一堆石頭數量不為2,其他石頭都為1.
如果我們有奇數堆數量為1的石頭,我們只用把那一堆數量不為2的石頭取完,對面就會面臨情況①。然後你就贏了2333.
如果我們有偶數堆數量為1的石頭,我們只用把那一堆數量不為2的石頭變成1,對面就會面臨情況①。然後你就贏了2333.
我們把上面兩種情況設為情況③(必贏)。
(是不是也很白癡)
好吧,我們再來看另外的情況,我們現在有大於等於2堆石頭數量不為2.
如果此時所有石頭異或和為奇數我們設為情況④
如果此時所有石頭異或和為偶數我們設為情況⑤
如果石頭異或和為奇數,我們可以取數量最多的那堆,使異或和變成偶數。此時④可以變成⑤
如果石頭異或和為偶數,我們必須取,此時異或和一定變為奇數,⑤又變成了④。然後我們是不是還可以取完一堆石頭,也就可能變成③。
所以情況④使對面狀態變成⑤,情況⑤會使對面面臨狀態⑤或③。
所以④(必贏),⑤(必輸)。
好了我們就知道了:②③④必贏,①⑤必輸,沒了。
AC代碼:
# include <cstdio> using namespace std; int T,n,ans,x,num; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); ans = num = 0; for(int i = 1;i <= n;i++){ scanf("%d",&x); if(!x)continue; ans ^= x; if(x >= 2)num++; } if((!num && !ans) || (ans && num))puts("John"); else puts("Brother"); } }
[Bzoj1022][SHOI2008]小約翰的遊戲John(博弈論)