![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /*
2 问题:
3 给你一些有向边 组成一个有向图
4 问这个图是不是一颗树
5 思路:
6 组成树的条件:
7 1.图按无向图计算 是连通的(并查集判断)
8 2.有且仅有一个顶点的入度为零(根节点)
9 3.除根节点外的其余顶点入度必须都为1
10 */
11 #include<iostream>
12 #include<cstring>
13 using namespace std;
14
15 bool flag[10010];//标记
16 int rd[10010];//记录每个点的入度
17
18 int rank[10010];//判断连通性
19 int father[10010];
20
21 int num;//记录顶点个数
22 bool f;
23
24 void init()
25 {
26 int i;
27 num=0;
28 f=0;
29 for(i=0;i<=10000;++i)
30 {
31 flag[i]=0;
32 father[i]=i;
33 rank[i]=1;
34 rd[i]=0;
35 }
36 }
37
38 int find(int x)
39 {
40 if(x!=father[x])
41 father[x]=find(father[x]);
42 return father[x];
43 }
44
45 void uion(int x,int y)
46 {
47 x=find(x);
48 y=find(y);
49 if(x==y)return ;
50 rank[x]+=rank[y];
51 father[y]=x;
52 }
53
54 int main()
55 {
56 int i,x,y,k=1;
57 while(cin>>x>>y&&(x!=-1||y!=-1))
58 {
59 if(!x&&!y)//注意这种情况
60 {
61 cout<<"Case "<<k<<" is a tree."<<endl;
62 k++;
63 continue;
64 }
65 init();
66 if(!flag[x]){num++;flag[x]=1;}
67 if(!flag[y]){num++;flag[y]=1;}
68 rd[y]++;
69 uion(x,y);
70
71 while(cin>>x>>y&&(x||y))
72 {
73 if(!flag[x]){num++;flag[x]=1;}
74 if(!flag[y]){num++;flag[y]=1;}
75 rd[y]++;// 记录每个点的入度数
76 if(rd[y]>1){f=1;continue;} //若有一个点的入度大于1则不是树
77 uion(x,y);
78 }
79
80 int d0=0;//判断入度为零的个数
81 if(!f)
82 {
83 for(i=0;i<=10000;++i)
84 {
85 if(flag[i]&&!rd[i])
86 {
87 d0++;
88 if(d0>1)// 若入度为0 的顶点个数超过1个则 不是树
89 {
90 f=1;
91 break;
92 }
93 }
94 }//for
95 }
96 if(!d0)f=1;// 有且仅有一个顶点的入度为零
97 if(!f)// a判断连通性
98 {
99 for(i=0;i<=10000;++i)
100 {
101 if(flag[i]&&rank[find(i)]!=num)
102 {
103 f=1;//不连通
104 break;
105 }
106 }
107 }
108 if(f)cout<<"Case "<<k<<" is not a tree."<<endl;
109 else cout<<"Case "<<k<<" is a tree."<<endl;
110 k++;
111 }
112 system("pause");
113 return 0;
114 }
115
116
优秀代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1
2 #include <stdio.h>
3
4 #define MAX 10000
5
6 int pre[MAX];
7 int tag[MAX]={0};
8
9 int find_parent(int x)
10 {
11 return pre[x]==x?x:(find_parent(pre[x]));//无压缩路径
12 }
13
14 int main()
15 {
16 int m,n,flag=0,sum=0,count=1,i;
17 for(i=1;i<=MAX;i++)
18 {
19 pre[i]=i;
20 tag[i]=0;
21 }
22 while(scanf("%d%d",&m,&n))
23 {
24 if(m==-1 && n==-1)
25 break;
26 if(m==0 && n==0)
27 {
28 if(flag==0)
29 {
30 for(i=1;i<MAX;i++)
31 {
32 if(tag[i]==0) continue;
33 if(pre[i]==i) sum++; //若连通则只有根节点的祖先是本身
34 }
35 if(sum>1) flag=1;//说明有孤立的点
36 }
37 if(flag==0)
38 printf("Case %d is a tree.\n",count++);
39 else
40 printf("Case %d is not a tree.\n",count++);
41 sum=0;
42 flag=0;
43 for(i=1;i<MAX;i++)
44 {
45 pre[i]=i;
46 tag[i]=0;
47 }
48 continue;
49 }//if(m==0 && n==0)
50 if(flag!=1)
51 {
52 int x,y;
53 x=find_parent(m);
54 y=find_parent(n);
55 tag[m]=1;
56 tag[n]=1;
57 if(x==y) flag=1;
58 else
59 {
60 if(pre[n]==n) pre[n]=x;//边(m,n),pre[n]==n;表明这是节点n第一次
61 //出现他的父节点m,则m 的祖先就n得祖先
62 // 把pre[n]=x;相当于 找到n最前的祖先
63 else flag=1;//若pre[n]!=n说明n有祖先且不是其现有父节点
64 //m的祖先(因x!=y)说明其入度大于1
65 }
66 }
67 }
68 //system("pause");
69 return 0;
70 }
71