题目描述:
http://acm.hdu.edu.cn/showproblem.php?pid=1325
中文大意:
有向树的性质:
1.只有一个入度为 0 的点,做为根节点
2.除根节点外,其余点的入度只能为 1
3.全部点都能连通,即全部点都在一个集合中(使用并查集来划分集合)
你将获得几组点边描述,要求判断所给数据是否构成了一棵有向树。
思路:
数组 in_degree[] 用来记录各节点的入度数。
若入度为 0 的节点有多个、或者没有,则不满足性质1;
若有些节点的入度数大于 1,则不满足性质2;
若树的节点个数 != 边的条数 + 1,则说明所给数据构成了不止一棵树,即所给图不连通,不满足性质3。
代码:
//测试用例:
//1 1 0 0
//1 2 3 2 0 0
//1 2 2 3 3 1 0 0
//1 2 3 4 0 0
//0 0
//
//false
//false
//false
//false
//false
#include<bits/stdc++.h>
using namespace std;
#define MAX 100001
int pre[MAX];//各节点的所属集
int cnt[MAX];//各集合中节点的数量
bool visited[MAX];//节点是否被访问
int in_degree[MAX];//节点的入度数
int points,edges;//点的个数、边的条数
int k;//Case k
//初始化
void init(){
k++;
points = 1;
edges = 0;
for(int i=1;i<MAX;i++){
pre[i] = i;
cnt[i] = 1;
visited[i] = false;
in_degree[i] = 0;
}
}
//寻找节点 x 的所属集
int find(int x){
if(x == pre[x]){
return x;
}
int root = find(pre[x]);
pre[x] = root;
return root;
}
//合并
void union_set(int x, int y){
//将节点 x 和节点 y 标记为已被访问,并且节点 y 的入度数加一
visited[x] = true;
visited[y] = true;
in_degree[y]++;
x = find(x);
y = find(y);
//x 和 y 在同一个集合中
if(x == y){
return;
}
//合并优化
if(cnt[x] <= cnt[y]){
pre[x] = y;
cnt[y] += cnt[x];
//集合中节点的个数
points = (points>cnt[y])?points:cnt[y];
}
else{
pre[y] = x;
cnt[x] += cnt[y];
points = (points>cnt[x])?points:cnt[x];
}
//在集合中添加了一个节点,所以边数加一
edges++;
}
//有向树的性质:
//1.只有一个入度为 0 的点,做为根节点
//2.除根节点外,其余点的入度只能为 1
//3.全部点都能连通,即全部点都在一个集合中(使用并查集来划分集合)
bool check(){
//树的特性:点的个数 = 边的个数 + 1
//若不满足该条件,则说明存在着不止一棵树,即有多个集合
if(points != (edges + 1)){
return false;
}
int root_num = 0;
for(int i=1;i<MAX;i++){
if(visited[i]){
if(in_degree[i] == 0){
root_num++;
//有多个根节点:1 2 3 2 0 0
if(root_num > 1){
return false;
}
}
else if(in_degree[i] > 1){//有些节点的入度数大于一
return false;
}
}
}
//没有根节点
if(root_num == 0){
return false;
}
return true;
}
int main(){
int x,y;
k = 0;
init();
//注意结束条件是:x < 0 || y < 0,而不是 x == -1 && y == -1
while(scanf("%d %d", &x, &y) && (x >= 0 && y >= 0)){
if(x == 0 && y == 0){
bool is_tree = check();
if(is_tree){
printf("Case %d is a tree.
", k);
}
else{
printf("Case %d is not a tree.
", k);
}
init();
continue;
}
union_set(x, y);
}
}