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

    并查集

    并查集运用树的结构,通过判断每个点的最终双亲是否相同来判断是不是在一个集合中

    一般步骤:

    1.查找:查找一个点的最终双亲---递归

    2.合并:如果两个相通点的双亲相同,说明已经在一个集合中,不需要合并,不同则将两个集合合并

     

    例题:村村通

    给定n个村庄和m条已经通的路,问还需要在休几条路

    思路:将通的路算作一个集合,求出有几个独立的集合

    将村庄比较树的结点,与它相通则表示为它的孩子;

    int par[N] 记录每个村庄的最终双亲

    首先将每个村庄的双亲记为自己:

    void init(int n) {
        for (int i = 0; i <= n; i++) {
            par[i] = i;
            Rank[i] = 1;
        }
    }
    View Code

    然后开始输入相通的村庄,并进行合并---其中Rank[] 的作用记录每科树的深度,使得在合并时让大树作为小树的双亲(减小树的深度)

    int find(int x) {//找最终双亲
        if(par[x] == x) return x;
        else return par[x] = find(par[x]);
    }
    
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if(x == y) return ;
    
        if(Rank[x] <= Rank[y]) par[x] = y;
        else par[y] = x;
        if(Rank[x] == Rank[y]) Rank[x]++;
    }
    View Code

    此时所有集合都已经找到了,我们只需要遍历每一个村庄,如果每个村庄的双亲就是自己说明它是集合的根节点 ans++;

    最后ans就是集合的个数,要想让所有集合相通 需要添加 ans-1 条路。

     

    全部代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1010;
    int par[N], Rank[N]; //par 祖先,Rank秩优化
    
    void init(int n) {
        for (int i = 0; i <= n; i++) {
            par[i] = i;
            Rank[i] = 1;
        }
    }
    
    int find(int x) {
        if(par[x] == x) return x;
        else return par[x] = find(par[x]);
    }
    
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if(x == y) return ;
    
        if(Rank[x] <= Rank[y]) par[x] = y;
        else par[y] = x;
        if(Rank[x] == Rank[y]) Rank[x]++;
    }
    
    bool same(int x, int y) {
        return find(x) == find(y);
    }
    //init(int) 初始化,unite(x,y) 合并 same 是否相同
    // find() 找祖先
    int main()
     {
         int n,m;
         while(cin>>n)
         {
             if(n==0) break;
             cin>>m;
             init(n);
             for(int i=1;i<=m;i++)
             {
                 int x,y;
                 cin>>x>>y;
                 unite(x,y);
             }
             int ans = 0;
             for(int i=1;i<=n;i++)
             {
                 if(i==find(i)) ans++;
             }
             cout<<ans-1<<endl;
         }
    
        return 0;
        }

     

  • 相关阅读:
    两种数组,注意用法
    PD 导出数据库结构
    获取随机金额:上限下限都要取到
    mysql常用语句
    SQL替换字符串、条件查询
    jtopo树结构方法积累
    jtopo 学习
    .net C# SortedList用法
    .net C# List用法
    .Net中C# Dictionary 用法(转)
  • 原文地址:https://www.cnblogs.com/subject/p/12386581.html
Copyright © 2011-2022 走看看