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);//合并两个节点
  • 相关阅读:
    Javaの网络数据传输之Socket
    AndroidのActivity跳转数据通信和跳转动画
    Androidの系统服务之getSystemService
    AndroidのUI设计研究(一)——自定义ProgressBar
    AndroidのService与Activity的及时通信
    Javaの网络数据传输之Http消息格式
    AndroidのActivity之后台隐藏
    《大道至简》读后感
    第一周
    第四周
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/14241195.html
Copyright © 2011-2022 走看看