并查集的利用

https://leetcode-cn.com/problems/number-of-provinces/
.https://www.nowcoder.com/test/question/done?tid=48978417&qid=1795704#summary

力扣547:
class UnionFind{
public:
    int find(int x){
        int root = x;
        
        while(father[root] != -1){
            root = father[root];
        }
        //其实在这里已经找到了root了,下面这一步其实是路径压缩
        
        while(x != root){
            int original_father = father[x];
            father[x] = root;
            x = original_father;//去让自己的爸爸参与压缩,这样可以压缩很多个节点
            //实现许多的节点以度为1指向这个根
        }
        
        return root;
    }
    
    bool is_connected(int x,int y){
        return find(x) == find(y);//压缩路径
    }
    
    void merge(int x,int y){
        int root_x = find(x);//每一次merge都会动态的压缩路径
        int root_y = find(y);
        
        if(root_x != root_y){
            father[root_x] = root_y;
            num_of_sets--;
        }
    }
    
    void add(int x){
        if(!father.count(x)){
            father[x] = -1;
            num_of_sets++;
        }
    }
    
    int get_num_of_sets(){
        return num_of_sets;
    }
    
private:
    // 记录父节点
    unordered_map<int,int> father;
    // 记录集合数量
    int num_of_sets = 0;
};

class Solution {
public:
    int findCircleNum(vector<vector<int>>& isConnected) {
        UnionFind uf;
        for(int i = 0;i < isConnected.size();i++){
            uf.add(i);
            for(int j = 0;j < i;j++){//保证了j比i小,说明j已经是建好的
                if(isConnected[i][j]){
                    uf.merge(i,j);
                }
            }
        }
        
        return uf.get_num_of_sets();
    }
};
2021腾讯校招
现在有107个用户,编号为1- 107,现在已知有m对关系,每一对关系给你两个数x和y,代表编号为x的用户和编号为y的用户是在一个圈子中,例如:A和B在一个圈子中,B和C在一个圈子中,那么A,B,C就在一个圈子中。现在想知道最多的一个圈子内有多少个用户。 

输入描述:
第一行输入一个整数T,接下来有T组测试数据。
对于每一组测试数据:第一行输入1个整数n,代表有n对关系。
接下来n行,每一行输入两个数x和y,代表编号为x和编号为y的用户在同一个圈子里。
1 ≤ T ≤ 10
1 ≤ n ≤ 105
1 ≤ x, y ≤ 107

输出描述:
对于每组数据,输出一个答案代表一个圈子内的最多人数

输入例子1:
2
4
1 2
3 4
5 6
1 6
4
1 2
3 4
5 6
7 8



#include <bits/stdc++.h>
#include<iostream>
using namespace std;
#include"unordered_map"
class Union {
public:
    Union() {
        children.resize(10000000, 0);
    }
    void merge(int x, int y) {
        int root_x = find(x);
        int root_y = find(y);
        if (root_x != root_y) {
            father[root_x] = root_y;
            children[root_y]=children[root_x]+1+children[root_y];
            //得放在里面,两个一样就不用减了
            num_union--;
        }

    }
    int inconnect(int x, int y) {
        return find(x) == find(y);
    }
    int find(int x) {
        int root = x;
        while (father[root] != -1) {//根节点的father是-1,不指向其他人
            root = father[root];
        }
        if (root == x) return root;
        //压缩
        while (father[x] != root) {//就这一行写 while(father[x]!=root)就tl了....
        //你想想看如果输入一个根节点,不就死循环了么,那么我们可以在上面判断是不是根节点,是就不用压缩了
            int temp = father[x];
            father[x] = root;
            //children[root]++;
            x = temp;
        }
        return root;
    }
    void add(int x) {
        //记得特判
        if (!father.count(x)) {
            father[x] = -1;
            num_union++;
        }

    }
    int get_num() {
        return num_union;
    }
    int get_a_union_num(int root) {//得到这个以root为根的群的数量
       // cout<< children[root]<<endl;
        return children[root]+1;
    }
public:
    unordered_map<int, int>father;
    int num_union = 0;
    vector<int>children;
};
int main() {
   
    int n;
    cin >> n;
    while (n > 0) {
        Union k;
        int num;
        int ans = -10;
        cin >> num;
        for (int i = 1; i <= num; i++) {
            int a, b;
            cin >> a >> b;
            k.add(a);
            k.add(b);
            k.merge(a, b);//以最后加入这个为根
         ans=max(ans,k.get_a_union_num(k.find(a)));
        }
        cout << ans << endl;
        n--;
    }

}

六大基本操做:
1.查根
2.查询是否在一个union
3.合并
4.增加节点
5.返回union数量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值