1. 程式人生 > >BZOJ 1022(博弈論)

BZOJ 1022(博弈論)

傳送門

題面:

1022: [SHOI2008]小約翰的遊戲John

Time Limit: 1 Sec  Memory Limit: 162 MB
Submit: 3445  Solved: 2222
[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
1
1

Sample Output

John
Brother

題目分析:

    SG博弈第一題?!第一眼看過去貌似是個Nim博弈?!寫了一發果斷wa......

    實際這是一個經典的Anti-SG遊戲的模型。

    Anti-SG遊戲即為滿足下列條件的博弈:

        1、決策集合為空的操作者勝。
        2、其餘規則與SG遊戲一致。

    對於Anti-SG遊戲,我們可以通過SJ定理進行解決:

    SJ定理

        對於任意一個Anti-SG遊戲,如果定義所有子游戲的SG值為0時遊戲結束,先手必勝的條件:
        1、遊戲的SG值為0且所有子游戲SG值均不超過1。
        2、遊戲的SG值不為0且至少一個子遊戲SG值超過1。

    證明:

         我不會證明,借鑑一下大佬的證明。

程式碼:

#include <bits/stdc++.h>
using namespace std;
int n;
bool check(){
    int SG=0;
    bool flag=false;
    for(int i=0;i<n;i++){
        int num;
        scanf("%d",&num);
        if(num!=1) flag=true;
        SG^=num;
    }
    if((SG!=0&&flag)||(SG==0&&!flag)) return true;//通過SJ定理進行判斷
    else return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        if(check()) puts("John");
        else puts("Brother");
    }
}