并查集c++

并查集

概念

一张图,想要判断其中两个点是否连通,用遍历来判断非常耗时。这时我们只需要把所有节点向上回溯,找到一个“最老的祖先”,然后当需要判断时,判断祖先是否一致就可以了,即判断是否在一个并查集内。

当我们想要合并两个并查集时,只需要将其中一个并查集的“祖先”与另一个并查集创建连通关系就可以了。

代码

首先是初始化。一开始时,我们不知道那些节点是连通的,因此每个点的祖先都是他自己。

因此对于每个f[i],它的初始值都是i。

void init(){
    for(int i=1;i<=n;i++)
        f[i]=i;
}

 然后是寻找节点的祖先。对于任意一个节点,其祖先和其父亲节点的祖先必然是一致的。因此寻找时只需要不断向上寻找父亲节点,直到找不到为止即可。

int fd(int x){
	if(f[x]==x)
        return x;
	return f[x]=fd(f[x]);
}

最后是合并。只需要把一个元素的祖先设为另一个元素的祖先即可。

void Union(int x,int y){
    x=fd(x);
    y=fd(y);
    f[x]=y;
}

例题

edu_student

这个题就是将所有亲戚创建联通关系,然后判断是否为一个并查集。

代码如下:

#include<bits/stdc++.h>
#define TIE ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
int n,m,p,a,b,c,d,f[5005];
void init(){for(int i=1;i<=n;i++)f[i]=i;}
int fd(int x){
	if(f[x]==x)return x;
	return f[x]=fd(f[x]);
}
void Union(int x,int y){x=fd(x);y=fd(y);f[x]=y;}
signed main(){
	TIE;cin>>n>>m>>p;init();
	for(int i=1;i<=m;i++){cin>>a>>b;Union(a,b);}
	for(int i=1;i<=p;i++){
		cin>>c>>d;
		if(fd(c)==fd(d))cout<<"Yes\n";
		else cout<<"No\n";
	}
	return 0;
}

 

带权并查集

点带权并查集

edu_student

在这道题中,我们不只需要判断其是否为同一个家族,还需要判断家族大小。

 我们可以额外创立一个数组,来记录每个家族的大小。

在开始时,因为还不清楚每个人家族的情况,因此对于每个人,家族大小都初始化为1。

合并时,不只要改变祖先,a家族并入b家族时,b家族的大小也应该改变。

这就是点带权并查集。

以下为代码:

#include<bits/stdc++.h>
#define TIE ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N=1e5+5;
int n,m,a,b,f[N],nm[N];string s;
void init(){
    for(int i=1;i<=n;i++){f[i]=i;nm[i]=1;}
}
int fd(int x){
	if(f[x]==x)return x;return f[x]=fd(f[x]);
}
void Union(int x,int y){
	int fx=fd(x),fy=fd(y);
	if(fx==fy)return ;f[fx]=fy;nm[fy]+=nm[fx];
}
signed main(){
    TIE;cin>>n>>m;init();
    while(m--){
        cin>>s>>a;
        if(s=="Q2")cout<<nm[fd(a)]<<"\n";
        else if(s=="Q1"){
            cin>>b;
            if(fd(a)==fd(b))cout<<"Yes\n";
            else cout<<"No\n";
        }else{cin>>b;Union(a,b);}
    }
    return 0;
}

边带权并查集

edu_student

我们尝试用并查集来做这个题目。

首先可以建图,每个人跟他的传递对象建立关系,当出现环时说明游戏结束。

因此我们需要求出最小环的大小。

对于两个节点,如果他们处于同一个并查集中,但他们父亲节点却不相同,则说明他们在一个环内。

因为问的是大小,所以我们还需要直到环的大小。

记录路径长度,可以在递归寻找祖先时,开一个新的数组记录到根节点的长度。

代码丢了

这个题可以看出,并查集可以用于判断图是否有环。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值