题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1325
题目大意:给你n对数a、b。表示a是b的父亲节点,遇到a==0 && b==0 时结束。然后根据当前信息,判断是否能构成一棵树。
思路:然后注意三点就行了。
1.树只有一个根节点。
2.不能构成一个环状
3.父亲节点可以指向多个孩子节点,但是一个孩子节点不能被多个父亲节点所指
然后,弄一个flag=0,违反一点就置为1,就行了,唉
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100070;
int a;
int father[maxn];
int judge[maxn]={0}; //表示一个节点被指的次数,如果一旦被指次数大于等于2,说明不是树
int flag;
void make_set(int x)
{
for(int i=1;i<=x;++i)
{
father[i]=i;
}
}
int find_father(int x)
{
if(x!=father[x])
{
father[x]=find_father(father[x]);
}
return father[x];
}
void join(int x,int y)
{
int p,q;
p=find_father(x);
q=find_father(y);
if(p!=q)
{
father[q]=p;
}
judge[y]++; //y被指的次数加一
if(judge[y]==2) //一旦大于等于2,表明这不可能是树了
{
flag=1;
}
}
int main()
{
int a,b;
flag=0;
make_set(maxn-1);
int e=0;
while(scanf("%d %d",&a,&b),!(a<0 && b<0)) //循环读入父亲节点和孩子节点
{
if(a==0 && b==0) //读入结束,这个时候开始判断是否只有一个根节点
{
int temp;
int flag2=1; //树立2号旗帜
for(int i=1;i<=maxn-1;i++) //遍历所有的结点
{
if( i!=father[i] && flag2==1) //如果i!=father[i]表示找到一个根节点,第一次走这里
{
temp=father[i]; //用temp把根节点存起来
flag2=0;
}else if(i!=father[i] && flag2==0 && temp!=father[i]) //第二次之后走这里呗,如果遇到第二个树的根节点,代表又不是树了
{
flag=1;
}
}
e++;
if(flag==1) printf("Case %d is not a tree.\n",e); //如果flag被置为1,说明至少有一个条件不符合
else printf("Case %d is a tree.\n",e);
make_set(maxn-1); //重新初始化一下
for(int i=0;i<maxn;i++)
{
judge[i]=0;
}
flag=0;
continue;
}
int m=find_father(a); //找a的父亲结点
int n=find_father(b); //找b的父亲节点
if(m==n) flag=1; //如果a和b的节点相同,说明构成环了,flag置为1
join(a,b); //把a和b联合起来
}
return 0;
}