题目链接:HDU1325
这题和上一题 HDU1272十分相似,唯一不同就是这题是个有向图,并且只需要判定是不是树即可。
思路,树上没有环,这一点判定和上题一样,以及只能有一个根节点。注意有向图的父亲指向儿子,所有在合并两点的时候,这一点不要搞反了。
AC代码:
/*
2017年8月28日11:21:01
HDU1325
并查集入门,判定是不是树
AC
*/
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
const int maxn=1e4+10;
int pre[maxn];
int root[maxn];
bool circle;
void init(){
for(int i=1;i<=maxn;i++){
pre[i]=i;
root[i]=0;
}
circle=false;
}
int find(int x){
int r=x;
while(pre[r]!=r) r=pre[r];//查找到根节点为止
int i=x,j;
while(i!=r){
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void join(int x,int y){
int fx=find(x);
int fy=find(y);
if(fx==fy||fy!=y){//这个地方要注意,一个子节点只能有一个父亲
circle=true;
}
else if(fx!=fy) pre[fy]=fx; //子节点链到父节点上
//else circle=true; 判断环
}
int main(){
int kase=0;
while(true){
init();
int a,b;
scanf("%d%d",&a,&b);//empty tree
if(a<0&&b<0) break;
else if(a==0||b==0){
printf("Case %d is a tree.\n",++kase);
continue;
}
join(a,b);
while(true){
scanf("%d%d",&a,&b);
if(a==0&&b==0) break;
join(a,b);
}
for(int i=1;i<=maxn;i++){
if(find(i)!=i){
root[find(i)]++;
// printf("root[%d]=%d\n",find(i),root[find(i)]);
}
}
int rt=0;
for(int i=1;i<=maxn;i++){
if(root[i]>0) rt++;
}
if(rt>1) circle=true;
//printf("rt=%d\n",rt);
if(!circle)
printf("Case %d is a tree.\n",++kase);
else
printf("Case %d is not a tree.\n",++kase);
}
return 0;
}