樹形結構+博弈論 - hdu6105

 

Gameia

 

 

 

題意:給定一棵樹,Alice先塗色,圖的點變成白色,Bob在Alice後塗色,所塗點以及相鄰的點都變成黑色.
Bob能在任意時刻剪斷一條邊,但是隻能k次。如果所有點都被着色,有白色就是Alice贏,否則Bob贏。

 

數據範圍

T≤100
1≤N≤500
0≤K≤500
1≤Pii

 

思路

博弈論。因爲相鄰的點能都會變成黑色,可以在之前就將所有的點都變成只是兩兩相連的,這樣所有點着色後,
就沒有白色點。題意轉化爲求是否能把這棵樹劃分爲兩兩相鄰。
邊界條件:點的數目不能爲奇數,技能數k>=n/2-1。
統計是否兩兩能兩兩相鄰,以爲是一棵樹,所以只要統計除根之外是否有根節點沒有子節點就可以了。

 

官方題解

 

  • 如果Bob能把這棵樹分成若干兩個一組的點對,那麼Bob取得勝利,否則Alice獲勝。
  • 如果原樹不存在兩兩匹配的方案,Alice從樹葉開始,每次都染樹葉父節點,Bob被迫只能不斷的染葉子,Bob退化成一般玩家,因爲Bob做不做小動作都不會逆轉局勢,總會出現一個時間點Bob沒辦法跟上Alice的節奏而讓Alice染到一個周圍都已被染色的孤立點(因爲原樹不存在兩兩匹配的方案)
  • 如果原樹存在兩兩匹配的方案,而且Bob的小動作次數也足以把原樹分成兩兩的點對,那麼Bob顯然獲勝。
  • 如果原樹存在兩兩匹配的方案,而Bob的小動作不足以把樹分成兩兩的點對,Alice一定獲勝,因爲每次染某個葉子節點(該節點爲其父節點的唯一子節點),Alice總能迫使Bob不斷的做小動作以保證剩下的樹不會出現奇數節點的樹,且每次小動作割出一個點對(包含Alice剛染的點),最後有兩種情況。
  • 出現某個結點有>=2個子節點爲葉子節點。Alice染這個點,Bob跟不上Alice的節奏,出現孤點,Ailice取勝
  • 否則整個過程一定會持續到樹被染光或者Bob被Alice掏空導致做不了小動作進而被迫割出一塊size爲奇數的子樹(這棵樹顯然沒辦法兩兩匹配)而敗北。
  • Bob被允許“任意時刻”做小動作看似很厲害其實很雞肋,把問題改成“Bob只能在遊戲開始之前做小動作”會得到同樣的結論。

 

AC代碼

 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;
const int ma=1050;
bool fg;

vector<int> mp[ma];

int cal(int s)
{
    int sum=0,siz=mp[s].size();
    for(int i=0;i<siz;++i)
    {
        sum+=cal(mp[s][i]);
        if(sum>=2) fg=true;
    }
    if(mp[s].size()==0) return 1;
    return 0;
}

int main()
{
    int t;
    scanf("%d",&t);
    int n,k;
    while(t--)
    {
        scanf("%d%d",&n,&k);
        int x;
        for(int i=2;i<=n;++i)
        {
            scanf("%d",&x);
            mp[x].push_back(i);
        }
        fg=false;
        if(n%2!=0||k<n/2-1) fg=true;
        if(!fg) cal(1);

        if(fg) printf("Alice\n");
        else printf("Bob\n");

        for(int i=1;i<=n;++i)
            mp[i].clear();
    }
    return 0;
}

 

 

 

 

 

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