1. 程式人生 > >[AGC014D]Black and White Tree

[AGC014D]Black and White Tree

題目地址:

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");
}