[AGC014D]Black and White Tree

版权声明:本文为博主原创文章,需转载请联系博主。 https://blog.csdn.net/ezoixx130/article/details/81748355

题目地址:

AGC014D

题意:

给你一棵树,两个人轮流在上面染色,每个人每次会把一个节点染成黑色或者白色,当所有点都被染了色后,如果存在一个白色的节点,它的所有相邻的节点均为白色,则先手胜,否则后手胜,问先手必胜还是后手必胜。

题解:

考场上想出了一种乱搞做法:

显然若有一个节点,它有两个以上的儿子是叶子节点,那么先手染这个点为白色就必胜,我们称这种点为必胜节点。

然后我们考虑这样的情况:

若一个节点有且仅有一个儿子,且这个儿子还是叶子节点,那么先手一定可以在这个节点上染上白色,后手就一定要在叶子节点上染黑色。于是这两个节点就对我们的答案没有影响了,可以删去,因为这个点一定是白色节点。

当我们把这种点全部删掉后,我们在剩下的树上找是否存在必胜节点,若存在则先手必胜,若不存在则后手必胜。

注意如果删完点后只剩根那也是先手必胜。

关于删点的方法,我们只要找到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");
}

猜你喜欢

转载自blog.csdn.net/ezoixx130/article/details/81748355