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;
    }
    

      

      

  • 相关阅读:
    72. Edit Distance
    电脑常识
    java try·····catch·····异常处理学习
    java链接sqlserver数据库
    HTTP Status 500
    初识NDA
    Sublime Text_v2.02包含中文包以及使用方法
    ol 与ul 的区别
    word-break: break-all word-break:keep-all word-wrap: break-word三者的区别
    用deamon打开ISO文件,提示命令行错误!!
  • 原文地址:https://www.cnblogs.com/imzscilovecode/p/8646143.html
Copyright © 2011-2022 走看看