HDU-1325-Is It A Tree?
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1325
程序分析:
这道题跟小希的迷宫有很大的相似吧,只是一个是无向图一个是有向图。也是给你那些结点之间的信息,然后让你判断是不是一颗树罢了,用树的定义来判断吧,无环,n个结点最多有n-1条边,不然就会有环。只有一个入度为0的结点,不存在入度大于1的结点。这些也足以判断是否为一棵树了吧。不过要注意一些特殊数据的情况,空树也是树。比如输入0 0。
解决方法:
其实也可以不用并查集,这样就可以直接按照上面的条件来统计,就可以判断是不是一颗树了。方法有多种,都知道最好,但是得精通,这些天都是在练并查集,所以我就用了并查集的思想来做吧,我加了个条件判断就是判断他村不存在环,这个是用到:如果两个不同的结点的根结点都相同,这样就会存在一个环或者有一个结点的入度会变为2了。只好也就不符合树的定义了。
控制输入数据时有点坑爹,输入停止条件应该是 a < 0 || b < 0,因为这个WA了很多次,最后是老大帮我改了之后就A了,一直还以为是数组不够大或者输入函数那些没写好,原来就是这么一个小BUG。学东西吧,错的多,改对了就能学会多一点。
View Code
1 #include<iostream> 2 using namespace std; 3 4 const int Max = 100000+10; 5 int Far[Max]; 6 int Rank[Max]; //改为标记结点的入度 7 int Sign[Max]; 8 9 void Make_set(int n) 10 { 11 int i; 12 for(i=0; i<n; i++) 13 { 14 Far[i] = i; 15 } 16 memset(Rank, 0, sizeof(Rank)); 17 memset(Sign, 0, sizeof(Sign)); 18 } 19 20 int Find_set(int x) 21 { 22 if(Far[x] != x) 23 return Far[x] = Find_set(Far[x]); 24 return Far[x]; 25 } 26 27 void Unio(int a, int b) 28 { 29 a = Find_set(a); 30 b = Find_set(b); 31 if(a == b) 32 return; 33 //因为是有向图,合并方向必须只有一个 34 Far[b] = a; 35 /* 36 if(Rank[a] < Rank[b]) 37 Far[a] = b; 38 else if(Rank[a] > Rank[b]) 39 Far[b] = a; 40 else 41 { 42 Far[a] = b; 43 Rank[b]++; 44 }*/ 45 } 46 47 int main() 48 { 49 int a, b; 50 //初始化 51 int flag = 1; 52 int k = 1; 53 Make_set(Max); 54 while(cin>>a>>b ) 55 { 56 if(a < 0 || b < 0) 57 return 0; 58 if(a == 0 && b == 0) //待一组数据输入完毕后才输出结果 59 { 60 int ans = 0; 61 for(int i=1; i<Max; i++) 62 { 63 if(Sign[i] && Find_set(i) == i) //统计有几个连通分支 64 ans++; 65 if(Rank[i] > 1) //存在有入度大于一的结点就不是树了,是图 66 { 67 flag = 0; 68 break; 69 } 70 } 71 if(ans > 1) //连通分支大于1,表示是否为森林 72 flag = 0; 73 if(flag) 74 cout<<"Case "<<k++<<" is a tree."<<endl; 75 else 76 cout<<"Case "<<k++<<" is not a tree."<<endl; 77 //从新初始化 78 flag = 1; //表示为Yes 79 Make_set(Max); 80 continue; 81 } 82 if(a != b && Find_set(a) == Find_set(b)) //根节点相同,但叶子不同,表示a,b已存在路径,如果 83 { //仍增加一条路径则会存在环,则有第二天路径 84 //cout<<"No"<<endl; 85 flag = 0; 86 } 87 else 88 { 89 Sign[a] = 1; 90 Sign[b] = 1; 91 Rank[b] ++; //入度加一 92 Unio(a, b); //b的老大是a,只能是一个方向,因为是有向图 93 } 94 } 95 return 0; 96 }