K MUV LUV UNLIMITED Gym 102361K(樹上博弈詳解!)

鏈接

題意:兩人輪流取葉子,取到根的人獲勝
參考博客
本題其實花了很長時間去理解去看,之前真的不是完全明白爲什麼這樣,看了上面的那篇參考博客,我想我應該對博弈題有一點淺薄的認知了。而我自己寫的這一篇博客相當於我理解的一個過程,我覺得是寫的更加詳細了一點,僅供大家參考,說的內容還是很詳實的。

思路:打這場訓練的時候當時就根據題意推了很久,用的非常笨的方法,利用已知必勝態必敗態推導未知必勝態和必敗態,草稿紙上推演了很長時間,就是想盡辦法把必敗態轉化。失敗了。因爲太過於複雜。
在這裏插入圖片描述
下面介紹博客鏈接的方法,我認爲這個大佬講的真是非常之好,先貼一下。
在這裏插入圖片描述
我們最先考慮的肯定是單鏈的情況,可以很輕鬆的看出結論,1、那便是奇數態爲必勝,偶數爲必敗態。這是一個十分簡單輕鬆便可以得出的結論,但這個結論十分重要!是我們推導剩下情況的基礎。

對於較爲複雜的情況我們可以考慮這樣一個事情

假設這棵樹有不止一個兒子(也就是說非單鏈的情況)那麼在非一個兒子的那棵子樹上,對於每一個兒子,仍然需要解決的是類似於這棵樹的問題,也就是說,對於這棵樹每一個出現的分支,只需要判斷幾個兒子是否產生了必勝態,類似於這樣。

在這裏插入圖片描述
那麼對於每一個分支,我們都可以這樣分解,最後問題便轉化成了對於每一個分支(從葉子往上第一個分叉)的子節點,是否會出現必勝態也就是說對於每一個分支點是否出現了必敗態,因爲什麼?因爲先手的優勢就在於此,我們是是否輕鬆容易的通過先手優勢轉化爲對方的必敗態,而我們只要保證自己不是必敗態便可以。那麼現在出現了一個問題,必敗態是什麼?根據剛剛單鏈的推導情況我們就可以看出來,就是當所有這種分支的鏈爲偶數的時候,我們必敗,其餘我們必勝。

2、所以實際上,那篇博客中的第二種情況是不必去看的,我們只需要轉化成判斷所有個分支(從葉子往上第一個分叉)長度是否是偶數,如果有一個奇數,那麼我們便可以獲勝。

綜上所述:實際上我們第一種情況甚至都不用去判斷,我們堅持的唯一原則就是,判斷所有個分支(從葉子往上第一個分叉)長度是否是偶數即可

代碼:

int n ;
VI G[N];
int win;
int son[N];
void dfs(int x,int len){
    if(son[x] == 0){
        if(len % 2)win = 1;
        return ;
    }
    if(son[x] == 1){
        for(auto y : G[x]){
            dfs( y ,len + 1);
        }
    }
    else{
        for(auto y : G[x]){
            dfs( y , 1);
        }
    }
}

int main(){
    int _;
    for(scanf("%d" , &_); _ ; _--){
        scanf("%d" ,&n);
        win = 0;
        for(int i = 1; i <= n ; i ++)son[i] = 0,G[i].clear();
        for(int i = 2; i <= n; i ++){
            int x;
            scanf("%d", &x);
            G[x].pb(i);
            son[x] ++;
        }
        dfs(1,1);
        if(win) puts("Takeru");
        else puts("Meiya");
    }

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