[AGC014D]Black and White Tree
阿新 • • 發佈:2018-11-29
題目地址:
題意:
給你一棵樹,兩個人輪流在上面染色,每個人每次會把一個節點染成黑色或者白色,當所有點都被染了色後,如果存在一個白色的節點,它的所有相鄰的節點均為白色,則先手勝,否則後手勝,問先手必勝還是後手必勝。
題解:
考場上想出了一種亂搞做法:
顯然若有一個節點,它有兩個以上的兒子是葉子節點,那麼先手染這個點為白色就必勝,我們稱這種點為必勝節點。
然後我們考慮這樣的情況:
若一個節點有且僅有一個兒子,且這個兒子還是葉子節點,那麼先手一定可以在這個節點上染上白色,後手就一定要在葉子節點上染黑色。於是這兩個節點就對我們的答案沒有影響了,可以刪去,因為這個點一定是白色節點。
當我們把這種點全部刪掉後,我們在剩下的樹上找是否存在必勝節點,若存在則先手必勝,若不存在則後手必勝。
注意如果刪完點後只剩根那也是先手必勝。
關於刪點的方法,我們只要找到size=2的節點,打個標記即可。
不過好像是完美匹配的題?跑網路流?Dinic分層圖飛快?
程式碼:
#include <bits/stdc++.h> using namespace std; #define MAXN 1000001 int size[MAXN],cnt; vector<int> edge[MAXN]; void addedge(int u,int v) { edge[u].push_back(v); } void dfs1(int now,int father) { size[now]=1; for(int i=0;i<edge[now].size();++i) { if(edge[now][i]==father)continue; dfs1(edge[now][i],now); if(size[edge[now][i]]==2)size[edge[now][i]]=-1; else size[now]+=size[edge[now][i]]; } } void dfs2(int now,int father) { ++cnt; int num=0; for(int i=0;i<edge[now].size();++i) { if(edge[now][i]==father)continue; if(size[edge[now][i]]==1){++num;} if(size[edge[now][i]]!=-1)dfs2(edge[now][i],now); } if(num>=2){puts("First");exit(0);} } int main() { int n; scanf("%d",&n); for(int i=1;i<n;++i) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs1(1,0); dfs2(1,0); if(cnt==1)puts("First");else puts("Second"); }