POJ 1308(并查集) (Data_Structure)
满足一下条件是树:
(1)只有一个根;
(2)一个入度为0的节点,其他节点入度都为1
第一个用并查集,第二个搞个数组统计下就OK。
我用set来存点,因为这些点在输入中可能出现多次,用set只会存一次,set方便些啦!
代码:
#include <cstdio> #include <cstdlib> #include <set> #include <iterator> #define N 10001 using namespace std; set<int> s; set<int>::iterator iter; int father[N]; int degree[N]; void make_set(); int find_set(int x); void unin(int x,int y); int main() { int i,j,f,a,b,k,zero; bool fail; k = 1 ; while(scanf("%d%d",&a,&b) && (a!= -1 && b != -1)) { /* 空树也是树 */ if( a == 0 && b == 0) { printf("Case %d is a tree.\n",k++); continue; } /* 每组数据都得清空 set容器 */ s.clear(); s.insert(a); s.insert(b); /* 初始化 */ make_set(); unin(a,b); ++degree[b]; while(scanf("%d%d",&a,&b) && (a&&b)) { s.insert(a); s.insert(b); unin(a,b); ++degree[b]; } f = find_set(father[*s.begin()]); zero = 0 ;//统计有几个入度为 0 的点 fail = false; for( iter = s.begin(); iter != s.end(); ++iter) { /* 树的每个点的祖先都一样,否则不是树 */ if(f != find_set(father[*iter])) { fail = true; break; } /* 树不能有入度大于 1的节点,否则不是树 */ if(degree[*iter]>1) { fail = true; break; } else { /* 统计根 */ if(degree[*iter] == 0) ++zero; } } printf("Case %d ",k++); if(fail || zero != 1) { printf("is not a tree.\n"); } else printf("is a tree.\n"); } return 0; } void make_set() { int i; for(i= 1; i < N; ++i) { father[i] = i; degree[i] = 0; } } int find_set(int x) { int t; if(x != father[x]) father[x] = find_set(father[x]);//路径压缩 return father[x]; } /* 因为是树,合并是有方向的 */ void unin(int x,int y) { x = find_set(x); y = find_set(y); father[y] = x; }