• 【并查集】hdu 1325 Is It A Tree?


    题目描述:

    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);
        }
    }
    作者:老干妈就泡面
    本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    [Java123] JDBC and Multi-Threading 多线程编程学习笔记
    3:2D装换 [ 重点 ]
    2:属性选择器 + 结构伪类选择器 + 伪元素
    1:新增 H5 常用属性
    day2
    代码实操第一天
    1 滑动门
    css高级技巧
    11:网页布局总结
    10:定位
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/14483993.html
Copyright © 2020-2023  润新知