• (板子)并查集(递归+循环)


    并查集板子的luogu传送门

    并查集是一个十分实用的算法,经常可以实现类似图论中寻找强联通的效果。

    其实,常规并查集的思想十分简单:给每个数据维护一个数组 f,初始化都是这个数据自己。然后,

    如果要讲两个数据合并,我们只需要将其中一个数据i的 f[i] 更改为另一个数据j的 f[j],就相当于讲这两个数据进行了“合并”。

    这个时候,我们就将f[j](即j)作为这个集合的“老大”,以后加进来的元素都以它为元首进行集合判断。

    接下来考虑如何实现

    首先,我们要求算法可以找到这个集合的“老大”。于是很轻易的设计出了以下递归算法:

    int find (int k){
        if(f[k] == k)return k;
        else return find(f[k]);
    }
    //在引用处,加入元素x到元素y所在集合操作:
    f[x] = find(y);

    算法要求是实现了,可是时间效率呢?答案是:很容易被卡。

    どうして?(皇家翻译:为什么?)

    因为有时候,我们可能会出现下面这种情况:(懒,用了洛谷的图)

                                     

    没错,有些数据可以把你的时间复杂度卡为O(N),效率极低。

    だから,(皇家翻译:So,)

    如何解决?

    其实很简单:

    在找老大的时候把路径上的小弟的 f 也顺便直接改成老大,这样查询集合的时候就可以近似做到O(1)的复杂度。

    int find(int x){
        if(x == f[x]) return x;
        else return f[x] = find(f[x]); // 在这里更新路径上的小弟
    }

     其实就是把图变成下面这样:

                                                  

    通过以上这些操作,并查集就完成了。

    p.s:并查集也有循环版的,效率可能会比递归的快, 这里就不多说了

    int find(int x){
        while(x!=fa[x]) x = fa[x] = fa[fa[x]];
        return x;
    }

    End:luogu的AC模板代码贴一下呗:

    #include<bits/stdc++.h>
    using namespace std;
    
    int n,m,f[66666];
    int Find(int x){
        while(x != f[x])x = f[x] = f[f[x]]
        return x;
    }
    
    void unit(int x,int y){
        x = Find(x);
        y = Find(y);
        if(x != y)f[x] = y;
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n; i++)f[i] = i;
        for(int i = 1;i <= m; i++){
            int x,y,z;
            scanf("%d",&z);
            if(z == 1){
                cin >> x >> y;
                unit(x,y);//x的目前老大的老大变成了y最终的老大 
            }
            else if(z == 2){
                scanf("%d%d",&x,&y);
                if(Find(x) == Find(y))printf("Y
    ");
                else printf("N
    ");
            }
        }
        return 0;
    }
  • 相关阅读:
    springBoot 2.1.5 pom 文件 unknown 错误
    @HystrixCommand 不能被导包
    SQL数据库连接语句
    ADO.NET中COMMAND对象的ExecuteNonQuery、ExcuteReader和ExecuteScalar方法
    重载和重写的区别
    抽象类和接口的相同点和不同点
    结构详解
    简单工厂和抽象工厂的区别
    DataRead和DataSet的异同
    什么是Web Server
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12713965.html
Copyright © 2020-2023  润新知