zoukankan      html  css  js  c++  java
  • 算法详解 【并查集】

    并查集概述

    针对散列点的集合操作,将哪些点集合到一起,判定哪些点在一个集合是并查集的基本任务。

    • 缺点:对于每一个集合,只有一个“群主”,其他的都是 “群员”,群员之间没有层级之分。
    • ​ 对于每一个点 i 判定给定一个 pre[ i ];若两个点的 pre[ i ] 相等则属于一个集合,其中 pre[ i ] = i 的点为“群主”。除此之外,若有 pre[ i ] = pre[ pre[ j ] ],形成类似链式关系 , 则递归查找时将 pre[ j ] = pre[ i ],将子点全都归于“群主” 。
    • 注意:为了精确的找到某个群员的群主,并且将群员的 pre 全都对齐于群主,我们一般采用 Find( i ) 代替 pre[ i ]

    并查集基本操作

    初始化

    对于每一个点,它一个人属于一个集合,它是它自己的“群主”。

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

    点击并拖拽以移动

    查找

    对于每一个点,递归查找它的 pre[ ] , 直到最后满足 pre[ i ] = i

            int Find(int x)
            {
                if(x == pre[x]) return x;
                return pre[x] = Find(pre[x]);
            }
    

    归并

            void Union(int x,int y)
            {
                int a = Find(id[x]),b = Find(id[y]);
                if(a == b) return;
                pre[a] = b;
            }
    

    Almost Union-Find

    例题:Almost Union-Find,并查集+删除节点

    ​ 在并查集中删除一个节点是很麻烦的事情,所以我们引入一个新的东西,用 id[ i ] 代替原有的 i 进行并查集操作,如果有一个点我们想把它从某一个集合中拿出来,就重新给 i 定义一个新的 id[ i ]并将它的状态初始化,一般用(++n)。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e6+10;
    int pre[maxn],id[maxn],num[maxn],sum[maxn];
    int n,m;
    void init()
    {
        for(int i=1;i<=n;i++){
            pre[i]=id[i]=sum[i]= i;
            num[i]=1;
        }
    }
    int Find(int x)
    {
        if(x == pre[x]) return x;
        return pre[x] = Find(pre[x]);
    }
    void Union(int x,int y)
    {
        int a = Find(id[x]),b = Find(id[y]);
        if(a == b) return;
        pre[a] = b;
        num[b] += num[a];
        sum[b] += sum[a];
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF){
            init();
            int op,x,y;
            for(int i=1; i<=m; i++)
            {
                scanf("%d",&op);
                if(op==1){
                    scanf("%d%d",&x,&y);
                    Union(x,y);
                }
                else if(op==2){
                    scanf("%d%d",&x,&y);
                    if(Find(id[x]) != Find(id[y])){
                        num[Find(id[x])]--;
                        sum[Find(id[x])]-=x;
                        id[x] = ++n;
                        pre[id[x]] = id[x];
                        num[id[x]] = 1;
                        sum[id[x]] = x;
                        Union(x,y);
                    }
                }
                else if(op==3){
                    scanf("%d",&x);
                    printf("%d %d\n",num[Find(id[x])],sum[Find(id[x])]);
                }
            }
        }
        return 0;
    }
    
  • 相关阅读:
    CE6内核启动过程新角度
    Eboot 中给nandflash分区实现
    Feedsky 上 csdn blog 订阅数排名 (zz)
    c# 枚举 enum 类型
    64bit系统下操作注册表的注意事项 ZZ
    良方治奇病,Visual Studio正则替换大法 (转)
    关于23种设计模式的有趣见解
    NHibernate快速指南(一)
    网站、数据库的衍变之路(二) (转)
    网站、数据库的衍变之路(一) (转)
  • 原文地址:https://www.cnblogs.com/betternow/p/13383374.html
Copyright © 2011-2022 走看看