题意:简述就是说给我们一个树:树中有n个节点,每个节点都会有一个颜色。(用1~n之间不同的数字表示。)同时还说明了树中各个节点之间的关系。(用n-1个u,v表示。)现在问我们以哪个节点作为根,可以使得这个根下的所有子树都为纯色。(子树中的所有节点的颜色都相同。)如果有输出那个节点,如果存在多个答案只需输出任意解。如果没有就输出“NO”。
思路:这个题应该至少有两种解法。第一种是假设一个点为根然后用dfs遍历一遍它的子树,并且判断这个子树是否可以为根就行了。(但是,这种做法写的不好容易超时。而且代码实现也比较麻烦,需要先用邻接表存储整个树才行。)第二种是在直接使用结构体存储n-1对输入,然后在输入完颜色之后遍历一遍数组记录下每个节点与它相邻的节点中不同色的数量cnt[i](对于第i个节点有cnt[i]个相邻节点与节点i的颜色不同。)以及所有相邻节点中不同色的对数m,最后在遍历数组cnt,如果存在第i个节点cnt[i]==m。则第i个节点就是那个根,如果不存在那就可以直接输出“NO”了。因为已经说明了给我们的一定是一个树,所以,这也就是第二种做法的正确的基本。
在比赛中我原本是用第一种思路来解的,虽然当时是过了。但是,在重测时却在在60+组中超时了。虽然第二天我就把我原来的代码调完AC了。但我还是觉得那个代码又臭又长,所以,就不放出来了。(第一种思路可以在O(nlongn)时间复杂度内完成。)直接上第二个思路的代码,代码相对来说就比较精简。(第二种思路的时间复杂度是O(n)。)
代码:
#include<iostream>
#include<cstring>
#define MAX 100005
using namespace std;
struct edge{
int a,b;
};
edge E[MAX];//在这个结构体中用来存储输入,a,b之间相连。
int poit[MAX],cnt[MAX];
//用poit数组来存储每个节点的颜色。
//cnt存储与它相邻的点中颜色不同的数量。
int main()
{
int n;
while(cin>>n){
int m=0;
for(int j=1;j<n;j++)
cin>>E[j].a>>E[j].b;
for(int j=1;j<=n;j++)
cin>>poit[j];
memset(cnt,0,sizeof(cnt));
for(int j=1;j<n;j++){
if(poit[E[j].a]!=poit[E[j].b]){
cnt[E[j].a]++,cnt[E[j].b]++;
m++;
}
//m表示的是总对数,因为,输入不会重复,所以m才可以直接这样计数。
}
for(int j=1;j<=n;j++){
if(cnt[j]==m){
cout<<"YES"<<endl<<j<<endl;
goto end;
}
//如果找到了一个cin[j]==m那就找到这个根了。
}
cout<<"NO"<<endl;
end:;
}
}
总结: 总得来说这个题还是相当好的,目测这个就是正解了。代码实现没有什么难度,只是想要想到这一点比较麻烦。即使想不到这个方法。但是,对于一些人来说也可以使用强硬的代码水平来AC。