合并集合(并查集)+求集合的个数

只实现联通功能

地址:

836. 合并集合 - AcWing题库

描述:

思想:

 

//普通版的find()函数,返回祖宗节点
int find(int x) {
    if (x == p[x])  //如果x是祖先,则返回
        return x;
    else
        return find(p[x]);  //如果x不是祖先,那么就去问x的爸爸它的爸爸是不是祖宗节点
}

//路径压缩的find函数,返回祖宗节点
int find(int x) {
    if (x != p[x])  // x不是自身的父亲,即x不是该集合的代表
    //把x的父节点改为集合的祖宗节点,即把x路径上的点的父节点都变为祖宗节点(路径压缩)
    //find(p[x])的作用是通过不断递归找到祖宗节点赋值给x的父节点  
           p[x]=find(p[x]);                      
    return p[x];//返回x的父节点下标,即该集合的祖宗节点
}

 为什么不写p[x]=find(x)写成find(p[x])?

find(p[x])的作用是通过不断递归找到祖宗节点赋值给x的父节点  

 代码:

#include <iostream>
using namespace std;
int n,m;//n是节点数,m是要进行的操作数
const int N=1e5+10;
//存放节点的父节点
int p[N];
//返回祖宗节点+路径压缩
int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main(){
    cin>>n>>m;
    //根据题意,开始时每一个节点都是独立的集合
    for(int i=1;i<=n;i++) p[i]=i;//它的父亲节点==它自己,每个节点都是它所在集合的根节点
    for(int i=0;i<m;i++){
        //指令的形式 M a b
        char op;
        int a,b;
        cin>>op>>a>>b;
        //op=='M'集合合并
        if(op=='M'){
            //两个点不在同一集合
            if(find(a)!=find(b)) p[find(a)]=find(b);
        }
        //查询两点是否在同一集合
        if(op=='Q'){
            if(find(a)==find(b)) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
    }
    return 0;
}

实现统计集合(联通块)个数功能

地址:

活动 - AcWing

描述:

思想:

整体思路和上面差不多,只是在上面联通集合的基础上加入了size[]来方便记录集合中节点数

 总体上只在这两处发生改动

代码:

#include <iostream>
#include <cstring>
using namespace std;
int n,m;//n是节点数,m是要进行的操作数
const int N=1e5+10;
//存放节点的父节点
int p[N];
//size[i]数组只在i节点为集合的根节点是有效,且代表i节点所在集合节点数
int Size[N];
//返回祖宗节点+路径压缩
int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main(){
    cin>>n>>m;
    //根据题意,开始时每一个节点都是独立的集合
    for(int i=1;i<=n;i++) 
    {p[i]=i;//它的父亲节点==它自己,每个节点都是它所在集合的根节点
    Size[i]=1;
    }
    for(int i=0;i<m;i++){
        //指令的形式 Q1 a b   Q2 a    C a b
        string op;
        int a,b;
        cin>>op;
        //op=='C'集合合并
        if(op=="C"){
            cin>>a>>b;
            //两个点不在同一集合,这里是把a所在节点加到b里面
            if(find(a)!=find(b)) {
                Size[find(b)]+=Size[find(a)];
                p[find(a)]=find(b);
        }
        }
        //查询两点是否在同一集合
        if(op=="Q1"){
            cin>>a>>b;
            if(find(a)==find(b)) cout<<"Yes"<<endl;
            else cout<<"No"<<endl;
        }
        //查询集合中点的个数
        if(op=="Q2"){
            cin>>a;
            //找到a节点所在集合的根节点下标
            cout<<Size[find(a)]<<endl;
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值