标签:
题意:
多组测试数据, 每组数据有多个数对, 表示一条有向边(即第一个数是第二个数的父节点), 以 0,0 为一组测试数据结束标志。当输入-1,-1时测试结束。 从那些给出的信息中判断是否是一棵树。
分析:
1、只可以有一个根节点, 也可以是一个点都没有的空树;
2、除了根节点, 每个点只有一个父节点。
3、因为只可以有一个父节点, 所以我们可以把一个合法的关系对(一个父亲节点与孩子节点对)合并到一个集合里, 他们的父节点都标记为所属树的根节点, 那样我们方便判断是否成环。
4、判断是否成环, 成环不可以。
5、 还有一个很衰的地方, 注意不光输入-1,-1 测试结束, 只要输入两个数都小于0就结束。
#include<iostream> #include<cstdio> #include<string.h> #include<math.h> #include<algorithm> using namespace std; const int N = 10005; int a, b, n, mi, mx, sum, flag, v[N], pre[N]; int find(int x)//寻找x所属的树的根节点 { int r, i, j; r = x; i = x; while(r != pre[r]) r = pre[r]; while(pre[i] != r) { j = pre[i]; pre[i] = r; i = j; } return pre[x]; } int main() { n = 0; while(scanf("%d%d", &a, &b) != EOF) { memset(v, 0, sizeof(v));//记录所涉及的点 for(int i = 1; i <= N; i++) pre[i] = i; if(a < 0 && b < 0) break; else if(a == 0 && b == 0)//特殊处理, 空树 { printf("Case %d is a tree.\n", ++n); continue; } pre[b] = a; v[a] = 1; v[b] = 1; mi = min(a, b); mx = max(a, b); flag = 1; while(scanf("%d%d", &a, &b) != EOF) { if(a == 0 && b == 0) break; if(mx < a || mx < b) mx = max(a, b); if(mi > a || mi > b) mi = min(a, b); v[a] = 1; v[b] = 1; if(flag == 1) { int fx = find(a); int fy = find(b); if((fy != b) || (fy == fx))//若构成环, 或孩子节点已经有父节点了, 那就是不合法的边 flag = 0; else if(fy == b && fy != fx)//如果不构成环并且没有父亲节点, 那就是合法的, 加入 pre[b] = fx; } } int sum = 0; if(flag == 1) { for(int i = mi; i <= mx; i++)//判断是否存在多棵树 { if(v[i] == 1) { int fx = find(i); if(fx == i) { sum++; if(sum > 1) { flag = 0; break; } } } } } if(flag == 1) printf("Case %d is a tree.\n", ++n); else if(flag == 0) printf("Case %d is not a tree.\n", ++n); } return 0; }
标签:
原文地址:http://www.cnblogs.com/wd-one/p/4515462.html