HDU 5423 Rikka with Tree (树,详解)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5423


题面:

Rikka with Tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 667    Accepted Submission(s): 306


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

For a tree T , let F(T,i) be the distance between vertice 1 and vertice i .(The length of each edge is 1).

Two trees A and B are similiar if and only if the have same number of vertices and for each i meet F(A,i)=F(B,i) .

Two trees A and B are different if and only if they have different numbers of vertices or there exist an number i which vertice i have different fathers in tree A and tree B when vertice 1 is root.

Tree A is special if and only if there doesn't exist an tree B which A and B are different and A and B are similiar.

Now he wants to know if a tree is special.

It is too difficult for Rikka. Can you help her?
 

Input
There are no more than 100 testcases.

For each testcase, the first line contains a number n(1n1000) .

Then n1 lines follow. Each line contains two numbers u,v(1u,vn) , which means there is an edge between u and v .
 

Output
For each testcase, if the tree is special print "YES" , otherwise print "NO".
 

Sample Input
   
   
   
   
3 1 2 2 3 4 1 2 2 3 1 4
 

Sample Output
  
  
  
  
YES NO
Hint
For the second testcase, this tree is similiar with the given tree: 4 1 2 1 4 3 4


解题:

    题目意思也是蛮绕的。相似是指,两棵树顶点数相同,且每个点到根节点(1为根节点)的距离都相同。不同是指,顶点数不同或者两棵树上某个节点的父亲不一样。现要求判断一棵树是不是special,special的特征是,不存在与之相似或与之不同的树。一开始有点混,以为只要是链即可。实际上,这样会漏掉两种情况,链是不相似,且不不同的情况,应该是去找是否存在不同且相似的情况。存在输出“NO”,否则输出“YES”。

    那么什么是不同且相似呢?就是某个节点它有超过1个孩子,并且它至少还可以往下两层。那么,假设当前节点在x层,其左右孩子分别为a,b,b还有孩子,那么交换a,b的孩子。对于新的到的树,就是不同且相似的,即每个节点到根节点距离不变,但交换的孩子的父亲发生了改变。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct edge
{
	int next,to;
}store[2010];
int head[1005],cnt;
bool vis[1005];
//加一条从a到b的边
void addedge(int a,int b)
{
	//cnt为边的存储下标
	store[cnt].to=b;
	store[cnt].next=head[a];
	//head为个顶点指向的第一条边的下标
	head[a]=cnt++;
}
bool flag;
//flag为标记,y为上一点是否有超过一个孩子的标记
void dfs(int x,bool y)
{
	if(flag)return;
	//标记该点
	vis[x]=1;
	//如果上一节点有超过一个孩子
	if(y)
	{
		int num=0,tmp=head[x];
		while(tmp!=-1)
		{
			//那么只要当前节点还有孩子即可
			if(!vis[store[tmp].to])
			{
				flag=true;
				return;
			}
			tmp=store[tmp].next;
		}
	}
	//如果没有,就继续向下移
	else
	{
	  int tmp=head[x],num=0;
	  //数当前节点孩子数量
	  while(tmp!=-1)
	  {
	    if(!vis[store[tmp].to])
			num++;
		tmp=store[tmp].next;
	  }
	  //如果孩子数量大于1
	  if(num>1)
	  {
		  int tmp=head[x];
		  while(tmp!=-1)
		  {
			  if(!vis[store[tmp].to])
				  dfs(store[tmp].to,1);
			  tmp=store[tmp].next;
		  }
	  }
	  //如果孩子数量小于等于1
	  else
	  {
         int tmp=head[x];
		  while(tmp!=-1)
		  {
			  if(!vis[store[tmp].to])
				  dfs(store[tmp].to,0);
			  tmp=store[tmp].next;
		  }
	  }
	}
}
int main()
{
    int n,a,b;
	while(~scanf("%d",&n))
	{
	   memset(vis,0,sizeof(bool)*(n+1));
	   memset(head,-1,sizeof(int)*(n+1));
       cnt=0;
       for(int i=1;i<n;i++)
	   {
          scanf("%d%d",&a,&b);
		  //加边
		  addedge(a,b);
		  addedge(b,a);
	   }
	   flag=false;
	   //数根节点孩子数量
	   int num=0;
	   int x=head[1];
	   while(x!=-1)
	   {
          num++;
		  x=store[x].next;
	   }
	   if(num>1)
         dfs(1,1);
	   else
		 dfs(1,0);
	   if(flag)printf("NO\n");
	   else printf("YES\n");
	}
	return 0;
}


你可能感兴趣的:(搜索,树,BestCoder)