http://acm.hdu.edu.cn/showproblem.php?pid=1325
题意:输入 x, y 表示 x 到 y 有一条有向边,判断给出的所有边能否组成一棵树。
思路:组成树的条件是只有一个点入度为 0 ,所有点的入度都小于 2,可以用并查集判断树中的环, 开个数组保存每个点的入度。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int pre[100010];
int ind[100010];
bool vis[100010];
void Init(){
for(int i = 0; i <= 100010; i++){
ind[i] = 0;
pre[i] = i;
vis[i] = false;
}
}
int Find(int rt){
return rt == pre[rt] ? rt : pre[rt] = Find(pre[rt]);
}
int Union(int x, int y)
{
if((x ^ y) & 1){
pre[x] = y;
}
else{
pre[y] = x;
}
return 0;
}
int main()
{
int x, y, tt = 1;
while(~scanf("%d%d", &x, &y) && (x >= 0 || y >= 0)){
Init();
ind[y]++;
Union(x, y);
bool flag = (x != y || x == 0);
vis[x] = vis[y] = true;
int maxn = x > y ? x : y;
while((x || y) && scanf("%d%d", &x, &y) && (x || y)){
if(flag){
ind[y]++;
vis[x] = vis[y] = true;
maxn = x > maxn ? x : maxn;
maxn = y > maxn ? y : maxn;
x = Find(x);
y = Find(y);
}
if(x == y)
flag = false;
if(flag){
Union(x, y);
}
}
int cnt0 = 0, cnti = 0;
for(int i = 1; i <= maxn && flag; i++){
if(!vis[i])
continue;
if(ind[i] == 0)
cnt0++;
if(ind[i] >= 2){
cnti++;
}
if(cnt0 >= 2 || cnti >= 2){
flag = false;
break;
}
}
printf("Case %d is ", tt++);
if(flag){
printf("a tree.\n");
}
else{
printf("not a tree.\n");
}
}
return 0;
}