• 浅谈 并查集之模板


    并查集 - 模板

    并查集,顾名思义,就是能 并(合并)查(查询)集(集合)

    需求

    1. 合并集合 (一般会给你两个点,需要合并两点所在的集合)
    2. 询问两点是否在同一集合

    实现

    思想

    并查集是将某些点(可以为一个点)看作一个集合,然后有若干个集合。
    因为我们只是要合并集合以及询问两点是否在同一集合之内,所以集合内点的顺序是不需要关心的。
    也就是说,在一个集合的点内随便找出一个点作为(root),其余点皆是他的儿子,这样就可以将每一个集合储存起来并为下文做好铺垫

    合并

    合并极其简单,只需要将两个集合中的一个集合的(root)作为新集合的(root),另一个集合的(root)则作为新集合(root)的儿子。

    Code
    //......
    
    for(int i=1;i<=n;++i) f[i]=i;
    // 初始化f数组,f[i]记录i的父亲
    // 至于初始化的值,只要你能知道这个值代表ta没有爸爸而且不会与数据冲突就好
    
    //......
    
    int find(int x){
    	if(x==f[x]) return x; // ta没有父亲,所以ta是这个集合的root
    	return find(f[x]); // 接着寻找ta的爸爸所在集合的root (与寻找x所在集合的root等价)
    }
    //这个find()为查找节点x所在集合的root
    
    //......
    
    f[find(x)]=find(y);
    //合并,找到两点所在的集合,让其中的一个root作为另一个root的儿子
    
    //......
    

    询问

    询问依旧极其简单,只需要判断两点所在集合的(root)是否相等,相等则在一个集合内,不相等则在不同的集合内。

    Code
    //......
    
    if(find(x)==find(y)) // 相同,在同一集合内
        puts("Y");
    else // 不相同,不在同一集合内
        puts("N");
    // 判断两点各所在集合的root是否相同
    
    //......
    

    亿些优化

    1. 在查询的时候,若集合内节点(设节点个数为(n))形成一条链,则查询叶子节点的复杂度为(O(n)),那么多次查找则复杂度会爆炸。
      这时候,我们就需要一些优化,显然,我们可以压缩路径,在我们查询一个点((x))时,当找到这个集合的(root)的时候,我们可以直接把(x)作为(root)的儿子,这样再查询(x)节点的时候,我们就可以使用(O(1))的复杂度来解决了。
       //---Code---
       //......
       
       int find(int x){
           if(x==f[x]) return x;
           return (f[x]=find(f[x])); // 这里使用了高(qi)超(ji)技(yin)艺(qiao),将x的爸爸改为ta所处集合的root,下次查询效率将提升
       }
       
       //......
    
    1. 我不会了......

    代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <list>
    #include <map>
    #include <set>
    using namespace std;
    #define ull unsigned ll
    #define INF 0x3f3f3f3f
    #define ll long long
    #define GC getchar()
    #define R read()
    ll read(){
        char c=GC; ll s=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-f;c=GC;}
        while(c>='0'&&c<='9'){s=s*10+c-'0';c=GC;}
        return s*f;
    }
    int n,m;
    int op,x,y; 
    int f[10005];
    int find(int x){ //查询其所在集合的root
    	if(x==f[x]) return x;
    	return (f[x]=find(f[x]));
    }
    int main(){
    	n=R; m=R;
    	for(int i=1;i<=n;++i) f[i]=i; // 初始化
    	for(int i=1;i<=m;++i){
    		op=R; x=R; y=R;
    		if(op==1) f[find(x)]=find(y); // 合并
    		else if(op==2) if(find(x)==find(y)) puts("Y"); else puts("N");  //询问
    	}
        return 0;
    }
    
  • 相关阅读:
    安装Bind到CentOS(YUM)
    安装Ansible到CentOS(YUM)
    安装AB到CentOS(YUM)
    安装APACHE到CentOS(YUM)
    07 Spring Cloud Eureka是什么?
    06 Spring Boot Starter的介绍及使用
    05 Spring Boot项目搭建步骤(超详细)
    04 Spring Cloud开发环境的准备和Lombok安装步骤
    03 Spring Cloud和Dubbo的区别及各自的优缺点
    02 Spring Cloud 模块介绍
  • 原文地址:https://www.cnblogs.com/FUXyao/p/14016896.html
Copyright © 2020-2023  润新知