POJ 1308
hdu 1325
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 17384 | Accepted: 5956 |
Description
Input
Output
Sample Input
6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1
Sample Output
Case 1 is a tree. Case 2 is a tree. Case 3 is not a tree.
Source
题意:判断一个有向图是否是树
算法:并查集+入度
注意:判断点是否使用。
开始我选的是记录最大值和最小值,但是居然连样例都过不了,后来输出了中间变量才发现,中间有些点没有用。
所以还要开一个数组 used[] 判断下标是否使用过。
树的定义:1.所有使用过的下标全在一个连通分量中。
2.根节点的入度为 0 ,其它所有节点的入度为 1.
奇怪的地方:没有给出下标范围,1000居然过了。
/* B Accepted 240 KB 0 ms C++ 1875 B 2013-04-07 19:47:27 */ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1000; int p[maxn]; //存父亲节点 int r[maxn]; //存入度 bool used[maxn]; //判断下标是否使用 int Max, Min; //判断树中使用的下标的最值 void set() //初始化 { for(int x = 0; x < maxn; x++) { p[x] = x; //自己为自己的父亲节点 r[x] = 0; //各点独立 入度为 0 used[x] = false; //各点均未使用 } Min = maxn; Max = -maxn; } int find(int x) //找根节点 { return x == p[x] ? x : p[x] = find(p[x]); } void Union(int x, int y) //合并两点所在的树 { int fx = find(x); int fy = find(y); p[fy] = fx; } int main() { int a, b; int C = 0; //记录是第几组数据 while(scanf("%d%d", &a, &b) != EOF) { if(a == -1 && b == -1) break; set(); //初始化 p[b] = a; r[b]++; //处理第一对数据 Min = min(a, b); Max = max(a, b); used[a] = true; //标记使用 used[b] = true; int x, y; bool flag = true; while(scanf("%d%d", &x, &y) != EOF) { if(x == 0 && y == 0) { int root = 0, index; //记录根节点个数 和下标 for(int i = Min; i <= Max; i++) { if(used[i] && i == p[i]) //判断有几个根 { root++; index = i; } } if(root != 1) flag = false; //一棵树只能有一个根 if(flag) { for(int i = Min; i <= Max; i++) //判断入度情况,除了根节点,其它节点入度均为1 { if(i != index && used[i] && r[i] != 1) flag = false; } } if(flag) printf("Case %d is a tree.\n", ++C); else printf("Case %d is not a tree.\n", ++C); //printf("%d\n", root); //开始有些小错误 输出中间变量,找错误 break; //注意:易忘记 } if(find(x) != find(y)) Union(x, y); //如果不在同一棵树中,则合并 r[y]++; //入度+1 used[x] = true; //标记使用 used[y] = true; Min = min(Min, x); Min = min(Min, y); //更新最值 Max = max(Max, x); Max = max(Max, y); } } return 0; }