1. 程式人生 > >【AtCoder2376】Black and White Tree(博弈)

【AtCoder2376】Black and White Tree(博弈)

題意

A和B輪流給樹上的結點染色,A每次選擇沒染過的點染成白色,B每次選擇沒染過的點染成黑色,最後若所有白色都與黑色相鄰,則B勝,否則A勝。雙方以最優策略,求A勝還是B勝。

題解

A首先選擇葉子結點的父親u,則B只能選擇葉子結點(否則葉子節點染白後,永遠不可能與黑色相鄰),所以,如果存在u有兩個以上葉子結點,則A勝; 然後刪去u,則u的父親v,如果v沒有了子節點,v就成為新的葉子結點,A可繼續先前的操作,B永遠處於被動當中。 當遇到一下兩種情況時,A必勝

  • 當前結點u含有兩個或以上葉子結點
  • 若u為根,且u的所有子節點都被染為白色(這時把自己染為白色即可)

dfs處理一邊即可。

程式碼

#include
<cstdio>
#include<cstring> #include<vector> #include<algorithm> using namespace std; const int MAXN=100005; int N; vector<int> adj[MAXN]; int col[MAXN]; bool dfs(int u,int f) { if(adj[u].size()==1U) { col[u]=0;//標記為葉子結點 return false; } int cnt[
2]={0}; for(int i=0;i<(int)adj[u].size();i++) { int v=adj[u][i]; if(v==f) continue; if(dfs(v,u)) return true; cnt[col[v]]++; } if(cnt[0]>=2) return true;//葉子結點大於等於2 if(f==0&&(int)adj[u].size()==cnt[1]) return true
;//當前u為根,u的所有子節點均為白色 if(cnt[0]) col[u]=1;//如果有葉子結點,這個點染白 else col[u]=0;//這個點的子節點全部被染白(被刪去),當前u變為葉子結點 return false; } int main() { scanf("%d",&N); for(int i=1;i<N;i++) { int u,v; scanf("%d%d",&u,&v); adj[u].push_back(v); adj[v].push_back(u); } if(N==2) puts("Second"); else { bool ans; for(int i=1;i<=N;i++) if(adj[i].size()>1U) { ans=dfs(i,0); break; } puts(ans?"First":"Second"); } return 0; }