题意
每次给定两个节点a,b,代表从a -> b有一条右向边。然后问最后给定的这些边组合起来是不是一颗严格意义上的树型结构。首先树的性质有:
- 除根节点外,任意一个节点的入度只能是1。
- n个节点的树有且只有n-1条边
- 没有节点的树是一颗空树,一定要注意这个空树的情况
- 没有环
思路
利用并查集合并,每个小子树,合并之前统计每个入点的度数。最后合并完的时候去判断,首先先判断是不是有环状,一旦有环说明不是一棵树,然后再去判断每个点的入度,在判断一下边和节点的关系是不是满足
v = e+1,其实有环的情况一定有节点的度数一定不为1。所以可以不用单独去判环。
这道题和HDU1272差不多,应该说是HDU1272的加强版。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 1e6+5;
int s[maxn];
set<int>st;
int cnt[maxn];
bool flag;
void clear_set()
{
st.clear();flag = true;
for(int i = 0;i < maxn;i++){
s[i] = i;
}
memset(cnt,0,sizeof(cnt));
}
int find_set(int x)
{
int r = x;
while(r != s[r]){
r = s[r];
}
while(r != x){
int t = s[x];
s[x] = r;
x = t;
}
return r;
}
void union_set(int x,int y)
{
st.insert(x);st.insert(y);
cnt[y]++;
x = find_set(x);
y = find_set(y);
if(x == y){
flag = false;
}
else{
s[y] = x;
}
}
int main()
{
int n,m,k = 1;
while(cin >> n >>m){
if(n < 0 && m < 0){
break;
}
if(n == 0 && m == 0){
printf("Case %d is a tree.\n",k++);
continue;
}
int x = max(n,m);
clear_set();
union_set(n,m);
int sum = 1;
while(cin>>n>>m){
if(n == 0 && m == 0){
break;
}
sum++;
union_set(n,m);
x = max(x,max(n,m));
}
if(flag == false){
printf("Case %d is not a tree.\n",k++);
}
else{
for(int i = 0;i <= x;i++){
if(cnt[i] > 1){
flag = false;
}
}
if(flag == true && st.size() == sum + 1){
printf("Case %d is a tree.\n",k++);
}
else{
printf("Case %d is not a tree.\n",k++);
}
}
}
return 0;
}
愿你走出半生,归来仍是少年~