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 numberi 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(1≤n≤1000).
Then n−1 lines follow. Each line contains two numbers u,v(1≤u,v≤n) , 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 HintFor 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
#include
#include
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;i1)
dfs(1,1);
else
dfs(1,0);
if(flag)printf("NOn");
else printf("YESn");
}
return 0;
}