Gameia
題意:給定一棵樹,Alice先塗色,圖的點變成白色,Bob在Alice後塗色,所塗點以及相鄰的點都變成黑色.
Bob能在任意時刻剪斷一條邊,但是隻能k次。如果所有點都被着色,有白色就是Alice贏,否則Bob贏。
數據範圍:
T≤100
1≤N≤500
0≤K≤500
1≤Pi≤i
思路:
博弈論。因爲相鄰的點能都會變成黑色,可以在之前就將所有的點都變成只是兩兩相連的,這樣所有點着色後,
就沒有白色點。題意轉化爲求是否能把這棵樹劃分爲兩兩相鄰。
邊界條件:點的數目不能爲奇數,技能數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;
}