【AtCoder2376】Black and White Tree(博弈)
阿新 • • 發佈:2018-12-12
題意
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;
}