CodeForces 1110 G. Tree-Tac-Toe

CodeForces 1110 G. Tree-Tac-Toet

题目链接:https://codeforces.com/contest/1110/problem/G

题目大意

给你一棵树,其中一些点已经染上了白色,有的没有颜色
现在有两个玩家黑色,白色,白色为先手
他们可以在树上把没有染色的点染上自己的颜色,
胜利条件为形成一条有三个顶点为某人颜色的路径,
假设两人聪明绝顶,问最终是谁胜出或平手。

这道题一开始是想树形DP的,
可是状态不太好设,
转移也特别麻烦。
所以DP就弃了
但可以发现貌似能分类讨论来解决这道题。

手玩一下可以发现
如果有一个度数大于等于4的点,那白色必胜。

如果有一个度数为3的点,
且该点为白色或与之相连的点中有白色点,则白色必胜。
或者是与之相连的点中有两个度数都大于等于2,则白色必胜。

如果有一个度数为2的点,
且该点以及与之相连的点中有两个白色点,则白色必胜。

如果树的形态是一条链,且链的非边缘部分有白色点,则白色必胜
去掉以上的情况以后,
树的形态要么是一条链,要么是一条两端有度数为3的点的类似链的情况,
考虑到链中除度数为3的点中最靠近度数为3的点可以转化为白点。
剩下的情况就只有这么一种,

一个链,只有边缘部分被染成白色。

那么,显然
如果不是两端都为白色的话,必定平手
而两端如果都是白色,那么只有长度为奇数的,白色才会胜利。
反之平手

Code

#include <cstdio>
#include <cstring>
using namespace std;
int to[1000010],next[1000010],last[500010],len=0;
int map[500010],vt[500010],Wt[500010],Tu[500010],Th[500010];
int Dt[500010];
int dutW[500010],dutB[500010];
int main()
{
	//freopen("Tree.in","r",stdin);
	//freopen("Tree.out","w",stdout);
	int T,n,i,j,u,v,ans,now,nown,who,bz,Thall;char c;
	scanf("%d",&T);
	while(T--)
	{
		ans=0;len=0;Thall=0;
		memset(last,0,sizeof(last));
		scanf("%d",&n);nown=n;
		for(i=1;i<=n;i++) Wt[i]=map[i]=vt[i]=0;
		for(i=1;i<n;i++)
		{
			scanf("%d%d",&u,&v);
			len++;to[len]=v;next[len]=last[u];last[u]=len;
			len++;to[len]=u;next[len]=last[v];last[v]=len;
			vt[u]++;vt[v]++;
		}scanf("\n");
		now=n;
		for(i=1;i<=n;i++)
		{
			scanf("%c",&c);
			if(c=='W') map[i]=Wt[i]=1;
		}
		for(i=1;i<=n;i++)
		{
			for(j=last[i];j;j=next[j])
				Wt[i]+=map[to[j]];
		}
		for(i=1;i<=n;i++)
			if(Wt[i]+vt[i]>=4) ans=1;
		for(i=1;i<=n;i++)
		{
			Tu[i]=0;Th[i]=0;
			for(j=last[i];j;j=next[j])
			{
				Tu[i]+=(vt[to[j]]>=2);
				Th[i]+=(vt[to[j]]>=3);
			}
			if(vt[i]==3&&Tu[i]>=2) ans=1;
			if(vt[i]==2&&Tu[i]&&map[i]) ans=1;
			if(vt[i]==3) Thall++,nown-=3;
			else if(map[i]) Thall++;
		}
		if(nown%2==1&&Thall==2) ans=1;
		if(ans==1) {printf("White\n");continue;}
		printf("Draw\n");
	}
	return 0;
}
posted @ 2020-09-08 22:38  JY_Chen  阅读(107)  评论(0)    收藏  举报