zoukankan      html  css  js  c++  java
  • 并查集(Disjoint Set Union,DSU)

    定义:

    并查集是一种用来管理元素分组情况的数据结构。

    作用:

    查询元素a和元素b是否属于同一组

    合并元素a和元素b所在的组

    优化方法:

    1.路径压缩

    2.添加高度属性

    拓展延伸:

    分组并查集

    带权并查集

    代码如下:

    //带有路径压缩的并查集
    //一句话并查集(常用)
    int dsu(int x){
        return x==par[x]?x:(par[x]=dsu(par[x]));
    }
    //带有路径压缩和高度的并查集
    //ranks[i]代表以i为根的树的最大高度,若不存在则为0
    int rank[maxn];
    int par[maxn];
    void init(int n){
        for(int i=0;i<n;i++){
            par[i]=i;
            rank[i]=0;
        }
    }
    int dsu(int x){
        if(par[x]==x){
            return x;
        }else{
            return par[x]=dsu(par[x]);
        }
    }
    void union(int x,int y){
        int fx=dsu(x);
        int fy=dsu(y);
        if(fx==fy){
            return;
        }
        if(rank[fx]<rank[fy]){
            par[fx]=fy;
        }else if(rank[fx]>rank[fy]){
            par[fy]=fx;
        }else{
            par[fy]=fx;
            rank[fx]++;
        }
    }
    bool same(int x,int y){
        return dsu(x)==dsu(y);
    }
    poj1182 食物链
    //带权并查集解法
    /*
    模仿矢量计算来处理权值
    当我们知道x与祖先x1的关系,y与祖先y1的关系,x与y的关系时,求x1与y1的关系时,使用矢量 
    计算: 
    x1->x ->y ->y1
    */
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=50010;
    int par[maxn],ran[maxn];
    int dsu(int x){
        if(x==par[x]){
            return x;
        }else{
            int fx=dsu(par[x]);
            //一开始将par[x]写成了fx,一直wa
            //如果是fx,那么每一次都到最终的根节点,求解ran数组显然不正确
            ran[x]=(ran[x]+ran[par[x]]+3)%3;
            par[x]=fx;
            return par[x];
        }
    }
    int main()
    {
        int n,m;
        int ty,x,y,ans=0;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=n;i++){
            par[i]=i;
            ran[i]=0;
        }
        while(m--){
            scanf("%d%d%d",&ty,&x,&y);
            if(x==y&&ty==2){
                ans++;
            }
            else if(x>n||y>n){
                ans++;
            }
            else{
                int fx=dsu(x);
                int fy=dsu(y);
                if(fx==fy)
                {
                    if((ran[x]-ran[y]+3)%3!=ty-1){
                        ans++;
                        //这里如果不相等,说明这句话是错误的,continue
                        //一开始因为没写continue,一直wa
                        continue;
                    }
                }
                par[fx]=fy;
                ran[fx]=(-ran[x]+ty-1+ran[y]+3)%3;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    //分组并查集解法
    /*
    个人理解带权并查集就是多个并查集,
    然后一个set所代表的的关系不仅一种,
    所以对每个元素要用多重表示,在这个题目里
    就是+i*n来区分每个元素和另一些元素的不同关系
    */
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    const int maxn = 200000+10;
    int par[maxn];
    
    int dsu(int x){
        return x==par[x]?x:(par[x]=dsu(par[x]));
    }
    bool same(int x,int y){
        return dsu(x)==dsu(y);
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<=3*n;i++){
            par[i]=i;
        }
        int cnt=0;
        int x,y,ty;
        while(m--){
            scanf("%d%d%d",&ty,&x,&y);
            if(x<=0||x>n||y<=0||y>n){
                cnt++;
                continue;
            }
            if(ty==1){
                if(same(x,y+n)||same(y,x+n)){
                    cnt++;
                }else{
                    for(int i=0;i<3;i++){
                        int fx=dsu(x+i*n);
                        int fy=dsu(y+i*n);
                        par[fx]=fy;
                    }
                }
            }else{
                if(x==y||same(x,y)||same(y,x+n)){
                    cnt++;
                }else{
                    for(int i=0;i<3;i++){
                        int fx=dsu(x+i*n);
                        int fy=dsu(y+(i+1)%3*n);
                        par[fx]=fy;
                    }
                }
            }
        }
        printf("%d
    ",cnt);
        return 0;
    }
    

      

      

  • 相关阅读:
    求Mac 的adt插件!
    前端ajax异步传值以及后端接收参数的几种方式
    在eclipse中使用git clone 别人共享在Github的代码和上传到自己的仓库!
    Tomcat 配置虚拟路径保存、访问图片
    sssp-springmvc+spring+spring-data-jpa问题总结
    redis整合异常总结
    sssp-springmvc+spring+spring-data-jpa增删改查
    ssm+PageHelper实现分页查询
    微信小程序异常解析
    CentOS 7.4中firewall防火墙详解和配置以及切换为iptables防火墙
  • 原文地址:https://www.cnblogs.com/imzscilovecode/p/8646143.html
Copyright © 2011-2022 走看看