zoukankan      html  css  js  c++  java
  • 并查集模板

     并查集模板(寻找祖先用递归实现):

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e5+5;
     5 int fa[maxn];
     6 
     7 void init(int n){        //初始化函数
     8     for(int i=0;i<=n;i++)fa[i]=i;
     9 }
    10 
    11 int find(int x){        //寻找祖宗
    12     return fa[x]==x?x:fa[x]=find(fa[x]);
    13 }
    14 
    15 void unio(int x,int y){    //合并两点
    16     int dx=find(x),dy=find(y);
    17     if(dx!=dy)fa[dx]=dy;
    18 }

    并查集模板(寻找祖先用循环实现,速度上并没有发现显著提高,但学长说可以避免卡栈溢出,合并过程直接在主函数内实现):

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e5+5;
     5 int fa[maxn];
     6 
     7 void init(int n){
     8     for(int i=0;i<=n;i++)fa[i]=i;
     9 }
    10 
    11 int find(int x){
    12     int r=x,t;
    13     while(r!=fa[r])r=fa[r];        //先循环一遍寻找祖先
    14     while(x!=r){                //再循环一遍更新父亲结点
    15         t=fa[x];
    16         fa[x]=r;
    17         x=t;
    18     }
    19     return r;
    20 }
    21 
    22 int x=find(a),y=find(b);        //主函数中完全可以直接实现合并
    23 if(x!=y)fa[x]=y;

     

    带权并查集(仅记录集合元素个数):

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e5+5;
     5 int fa[maxn],num[maxn];
     6 
     7 void init(int n){
     8     for(int i=0;i<=n;i++){fa[i]=i;num[i]=1;}    //初始化每个集合元素个数为1
     9 }
    10 
    11 int find(int x){
    12     int r=x,t;
    13     while(fa[r]!=r)r=fa[r];
    14     while(x!=r){
    15         t=fa[x];
    16         fa[x]=r;
    17         x=t;
    18     }
    19     return r;
    20 }
    21 
    22 int x=find(a),y=find(b);
    23 if(x!=y){
    24     fa[x]=y;
    25     num[y]+=num[x];        //合并集合时在祖先结点上改合并后的集合元素个数
    26 }

      

    种类并查集(本质也是带权并查集,但是是记录元素的性质的,权值一般表示与父亲结点的关系):

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e5+5;
     5 int fa[maxn],num[maxn];
     6 
     7 void init(int n){
     8     for(int i=0;i<=n;i++){
     9         fa[i]=i;
    10         num[i]=0;        //此处表示和父亲节点的大小差距,初始化0
    11     }
    12 }
    13 
    14 int find(int x){                //这里压缩路径并更新结点权值的思想是先循环加每个结点到父节点的权值,再次循环时每次减去之前更新完的权值再更新
    15     int r=x,t1,t2,c=0;
    16     while(r!=fa[r]){
    17         c+=num[r];
    18         r=fa[r];
    19     }
    20     while(x!=r){
    21         t1=fa[x];
    22         t2=c-num[x];
    23         num[x]=c;
    24         fa[x]=r;
    25         c=t2;
    26         x=t1;
    27     }
    28     return r;
    29 }
    30 
    31 int x=find(a),y=find(b);
    32 if(x!=y){            //合并时的操作
    33     fa[x]=y;
    34     num[x]=num[b]+v-num[a];
    35 }

  • 相关阅读:
    JavaScript的数据类型
    php字符串操作
    PHP快速入门
    JavaScript简介与使用方法
    《技术大牛的养成指南》--读书笔记
    Java并发编程-多线程
    分布式锁的实现方式和优缺点&Java代码实现
    Java操作Zookeeper
    排序二叉树、平衡二叉树、红黑树
    HashMap&Hashtable&LinkedHashMap&ConcurrentHashMap&Collections.synchronizedMap
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4454367.html
Copyright © 2011-2022 走看看