版权声明:本文为博主原创文章,需转载请联系博主。 https://blog.csdn.net/ezoixx130/article/details/81748355
题目地址:
题意:
给你一棵树,两个人轮流在上面染色,每个人每次会把一个节点染成黑色或者白色,当所有点都被染了色后,如果存在一个白色的节点,它的所有相邻的节点均为白色,则先手胜,否则后手胜,问先手必胜还是后手必胜。
题解:
考场上想出了一种乱搞做法:
显然若有一个节点,它有两个以上的儿子是叶子节点,那么先手染这个点为白色就必胜,我们称这种点为必胜节点。
然后我们考虑这样的情况:
若一个节点有且仅有一个儿子,且这个儿子还是叶子节点,那么先手一定可以在这个节点上染上白色,后手就一定要在叶子节点上染黑色。于是这两个节点就对我们的答案没有影响了,可以删去,因为这个点一定是白色节点。
当我们把这种点全部删掉后,我们在剩下的树上找是否存在必胜节点,若存在则先手必胜,若不存在则后手必胜。
注意如果删完点后只剩根那也是先手必胜。
关于删点的方法,我们只要找到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");
}