zoukankan      html  css  js  c++  java
  • 算法-并查集

    并查集板子

    链接:https://ac.nowcoder.com/acm/problem/14685
    来源:牛客网
    题目描述
    给你一个 n 个点,m 条边的无向图,求至少要在这个的基础上加多少条无向边使得任意两个点可达~
    输入描述:
    第一行两个正整数 n 和 m 。
    接下来的m行中,每行两个正整数 i 、 j ,表示点i与点j之间有一条无向道路。
    输出描述:
    输出一个整数,表示答案
    示例1
    输入
    复制
    4 2
    1 2
    3 4
    输出
    复制
    1
    备注:
    对于100%的数据,有n,m<=100000。

    #include<iostream>
    #include<stdio.h>
    using namespace std;
    int uset[100005];	 // uset[i] 表示i的根节点
    int dep[100005];    // 集合数的秩(高度)
    
    // 并查集
    void init_uset(int n){
        // 将前n个节点的的父节点设置为自己,表示为这个集合中只有自己,
        for(int i = 1; i <= n; i++){
             uset[i] = i;
        }
    }
    
    int find_x(int x){
        // 查找根节点,并压缩路径(找到x的根节点后,直接将x连接到根节点既uset[i] = 根节点编号)
        if(x != uset[x]){
            uset[x] = find_x(uset[x]);
        }
        return uset[x];
    }
    
    void union_set(int x, int y){
        // 根据秩合并集合
        x = find_x(x);
        y = find_x(y);
        if(x == y){
            // 如果根节点相同,则不用合并
            return ;
        }
        if(dep[x] > dep[y]){	//将秩更小的树(高度更低)的根节点,作为更大的秩的树的根节点的子节点进行合并
            uset[y] = x;
        }else{
            uset[x] = y;
            if(dep[x] == dep[y]){
                dep[y] ++;
            }
        }
        
    }
    
    
    
    int main()
    {
        int n,m;
        cin >> n >> m;
        init_uset(n);
        int a,b;
        for(int i = 0; i < m; i++){
            scanf("%d%d", &a, &b);
            union_set(a, b);
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            if(uset[i] == i){	// 根节点的的父节点为自己,所以有几个uset[i] == i表示有几棵树
                ans ++;
            }
        }
        cout << ans - 1 << endl;
    }
    
  • 相关阅读:
    CSS练习
    大作业“抽屉页面”html+css
    html练习代码
    协程-基于TCP的高并发通信
    协程-爬虫示例
    互斥锁,递归锁,信号量
    三层架构(我的理解及详细分析)
    递归算法经典实例小结(C#实现)
    使用XmlWriter写Xml
    使用XmlReader读Xml
  • 原文地址:https://www.cnblogs.com/jlxa162hhf/p/14161216.html
Copyright © 2011-2022 走看看