zoukankan      html  css  js  c++  java
  • 并查集学习

    转自:https://zhuanlan.zhihu.com/p/93647900,写的太好,膜拜

    1.解决问题

    管理不相交的集合,解决元素分组问题。包括两种操作:

    • 合并(Union):把两个不相交的集合合并为一个集合。
    • 查询(Find):查询两个元素是否在同一个集合中。

    2.实现

    //具体的理解过程上述连接中有,很生动

    初始化:

    int fa[MAXN];
    inline void init(int n)
    {
        for (int i = 1; i <= n; ++i)
            fa[i] = i;
    }

     每个节点单独成集合,父节点都是自己。

     查询所在集合中的根节点:

    int find(int x)
    {
        if(fa[x] == x)
            return x;
        else
            return find(fa[x]);
    }

    递归查询,根节点的父节点是自身,查询的目的就是找到根节点,如果当前不是,那么就递归找当前节点父节点的根节点。

    合并集合: 

    inline void merge(int i, int j)
    {
        fa[find(i)] = find(j);
    }

    本函数是将i所在的集合合并到j。

    3.路径压缩

    上面中存在的问题是树的深度会很深,那么在查询的时候进行压缩,查询到集合所在的根节点之后,直接将当前节点的父节点设置为根节点,减少下次查询的路径长度。希望每个元素到根节点的路径长度尽可能短。

    查询(带路径压缩):

    int find(int x)
    {
        if(x == fa[x])
            return x;
        else{
            fa[x] = find(fa[x]);  //父节点设为根节点
            return fa[x];         //返回父节点
        }
    }

    简写:

    int find(int x)
    {
        return x == fa[x] ? x : (fa[x] = find(fa[x]));
    }

    //太牛了吧。

    4.改进:按秩合并

    记录每个节点所在的树的深度,在合并时将深度较小的合并到深度较大的集合中。

    5.类(按节点个数合并)

    参考力扣1631. 最小体力消耗路径官方题解提供的代码:

    // 并查集模板
    class UnionFind {
    public:
        vector<int> parent;
        vector<int> size;
        int n;
        // 当前连通分量数目
        int setCount;
        
    public:
        UnionFind(int _n): n(_n), setCount(_n), parent(_n), size(_n, 1) {
            iota(parent.begin(), parent.end(), 0);
        }
        
        int findset(int x) {
            return parent[x] == x ? x : parent[x] = findset(parent[x]);
        }
        
        bool unite(int x, int y) {
            x = findset(x);
            y = findset(y);
            if (x == y) {
                return false;
            }
            if (size[x] < size[y]) {
                swap(x, y);
            }
            parent[y] = x;//将节点少的合并到节点多的连通分量上
            size[x] += size[y];
            --setCount;//合并了之后就减少一个连通分量
            return true;
        }
        
        bool connected(int x, int y) {
            x = findset(x);
            y = findset(y);
            return x == y;
        }
    };
    //操作语句
    UnionFind uf(m * n);//初始化m*n大小的并查集
    uf.unite(x, y);//合并两个节点
  • 相关阅读:
    NB-IOT终端应用场景
    开关量是什么信号,模拟量是什么信号
    模拟量设备为什么都用4~20mA传输信号
    物联网三大关键技术
    4~20mA.DC(1~5 V.DC)信号制的优点
    Lora在局域网中的优势
    NB-IoT终端在不同工作状态下的分析
    4G模块的串行AT命令发送未接收返回如何处理
    前端性能优化
    Tab:不可思议的CSS光标下划线跟随效果
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/14241195.html
Copyright © 2011-2022 走看看