题面
题意
给出一棵树,初始有一些点被染成了白色而其他点没有颜色,现在有两个人A,B轮流操作,A会把某个未染色的点染成白色,B会把某个未染色的点染成黑色,若出现了一条长度为三,颜色相同的链,则对应颜色的人获胜,A先操作,请问哪一方会获胜。
做法
首先我们考虑转化一下初始为白色的节点,若点A为白色,则我们可以新建点B,C,D,并且连边(A-B),(B-C),(B-D),并将A变为未染色的点,不难发现两者等价,现在考虑如何处理没有点被染色的情况。
可以分成以下三种情况:
1.某个点的度数大于等于4,很显然,只要先手染这个点即可获胜。
2.某个点的度数为3,且有两个儿子不是叶子节点,同样先手必胜。
3.有两个点的度数为3,则若这两个点的距离为偶数,则先手必胜。先手只要先将这两个节点的父亲(唯一一个非叶子节点)染白,然后在这两条链上隔一个点染一下即可。
其余情况均为平局,显然黑方不可能赢。
代码
#include<bits/stdc++.h>
#define N 2001000
using namespace std;
int T,n,mx,tt,ds[N];
char str[N];
vector<int>to[N];
inline void add(int u,int v)
{
to[u].push_back(v);
to[v].push_back(u);
ds[u]++,ds[v]++;
}
int dfs(int now,int last,int fd)
{
if(now==fd) return 0;
int i,t,tmp;
for(i=0;i<to[now].size();i++)
{
t=to[now][i];
if(t==last) continue;
tmp=dfs(t,now,fd);
if(tmp!=-1) return tmp+1;
}
return -1;
}
inline bool work()
{
int i,j,p,q,cnt=0;
for(i=1;i<=n;i++)
{
if(ds[i]>=4) return 1;
if(ds[i]==3)
{
cnt++;
if(cnt==1) p=i;
else if(cnt==2) q=i;
int ct=0;
for(j=0;j<to[i].size();j++) if(ds[to[i][j]]>1) ct++;
if(ct>=2) return 1;
}
}
if(cnt<2) return 0;
return dfs(p,-1,q)%2==0;
}
int main()
{
int i,j,p,q,t;
cin>>T;
while(T--)
{
scanf("%d",&n);
tt=n;
for(i=1;i<n;i++)
{
scanf("%d%d",&p,&q);
add(p,q);
}
scanf("%s",str+1);
for(i=1;i<=n;i++)
{
if(str[i]=='W')
{
t=++tt;
add(i,t);
add(t,++tt);
add(t,++tt);
}
}
n=tt;
puts(work()?"White":"Draw");
for(i=1;i<=n;i++)
{
ds[i]=0;
to[i].clear();
}
}
}