zoukankan      html  css  js  c++  java
  • 算法笔记--数据结构--并查集

    并查集的定义

    • 合并:Union
    • 查找:Find
    • 集合:Set

    并查集其实就是一个数组

    int father[N];
    

    father[i]表示元素i的父亲结点,而父亲结点本身也是这个集合内的元素(1≤i≤N)

    father[i] = i说明元素i是根结点

    Snipaste_2020-04-15_17-59-17

    并查集的基本操作

    初始化

    for(int i = 1; i <= N; i++){
        father[i] = i;		// 初始时,每个元素都是独立的一个集合
    }
    

    查找

    int findFather(int x){
        if(x == father[x]) return x;
        else return Findfather(father[x]);
    }
    

    合并

    合并是指把两个集合合并成一个集合

    步骤

    1. 对于给定的两个元素a和b,判断他们是否属于同一个集合。即调用findFather函数对这两个元素查找根结点,然后再判断其根结点是否相同
    2. 合并两个集合:在上一步中已经获得了两个元素的根结点faA和faB,因此只需要把其中一个的父亲结点指向另一个结点
    void Union(int a, int b){
        int faA = findFather(a);
        int faB = findFather(b);
        if(faA != faB){
            father[faA] = faB;
        }
    }
    

    为了保证不产生环:只对不同集合进行合并。所以,并查集产生的每一个集合都是一棵树

    路径压缩

    当许多元素形成一条链时,查找函数的效率就会很低,所以要进行路径压缩

    Snipaste_2020-04-15_18-13-12

    把当前查询结点的路径上的所有结点的父亲都指向根结点

    步骤

    1. 按照原先的写法获得x的根结点r
    2. 重新从x开始走一遍寻找根结点的过程,把路径上经过的所有结点的父亲全部改为根结点r
    int findFather(int v){
        if(v == father[v]) return v; // 找到根结点
        else{
            int F = findFather(father[v]);
            father[v] = F;
            return F;
        }
    }
    

    例题

    Snipaste_2020-04-15_18-24-01

    Snipaste_2020-04-15_18-24-09

    #include<cstdio>
    
    const int MAXN = 110;
    bool isRoot[MAXN];
    int father[MAXN];
    
    void initial(int n){
        for(int i = 1; i <= n; i++){
            father[i] = i;
            isRoot[i] = false;
        }
    }
    
    int findFather(int x){
        if(x == father[x]) return x;
        else{
            int F = findFather(father[x]);
            father[x] = F;
            return F;
        }
    }
    
    void unions(int a, int b){
        int faA = findFather(a);
        int faB = findFather(b);
        if(faA != faB){
            father[faA] = faB;
        }
    }
    
    int main(){
        int n, m, a, b;
        scanf("%d%d", &n, &m);
        initial(n);
        for(int i = 0; i < m; i++){
            scanf("%d%d", &a, &b);
            unions(a, b);
        }
        for(int i = 1; i <= n; i++){
            isRoot[findFather(i)] = true;
        }
        int ans = 0;
        for(int i = 1; i <= n; i++){
            ans += isRoot[i];
        }
        printf("%d
    ", ans);
        return 0;
    }
    

    Write by Gqq

  • 相关阅读:
    屏蔽/捕获并输出错误
    物理机转Hyper-V虚拟机
    Windows Server 2012无法安装 .NET3.5-安装角色或功能失败,找不到源文件
    IDRAC 固件升级操:
    网卡启动安装dell服务器OS
    服务器指定网卡进行备份数据避免影响业务口
    【转载】用户通过WEB方式更改AD域帐户密码
    Windows运维之Windows8.1-KB2999226-x64安装提示 此更新不适用你的计算机
    Exchange 退信550 5.1.11 RESOLVER.ADR.ExRecipNotFound
    优酷kux视频转MP4
  • 原文地址:https://www.cnblogs.com/zgqcn/p/12707252.html
Copyright © 2011-2022 走看看