教授先生带你学习并查集

//1、初始化 
int fa[MAXN];
void init(int n)
{
	for(int i=1;i<=n;i++)
	    fa[i]=i;
 } 

假设有编号从1到n个元素,我们用一个数组fa[]来存储每个元素的父节点。一开始我们先将他们的父节点设为自己 (自己的祖先就是自己)如:fa[1]=1, fa[2]=2 

                             如果fa[1]=fa[2]=2 ,则fa[1]=2,数组fa[1]的值变成了2,表示节点1的祖先是2

//2、查询 
  int find(int i)//找i的祖先代表的元素 
  {
  	if(fa[i]==i)//递归出口,到达了祖先位置,就返回祖先
  	     return i;
    else 
	  return find(fa[i]); //不断往上查找祖先 
   } 

 每一次查询某个节点的祖先是谁,通过多次递归的方式寻找到某个节点的最终祖先

//3、合并
void unionn(int i,int j)
{
	int i_fa=find(i);//找到i的祖先 
	int j_fa=find(j);//找到j的祖先 
	fa[i_fa]=j_fa//i的祖先指向j的祖先。 
}

 (4,3)  (3,2)  (2,1) 分别将4,3 ;3,2;2,1当作i和j执行函数,将4,3,2,1每个节点连接起来,最后,4,3,2,1和1的祖先都是1.

 添加路径压缩的核心代码 fa[i]=find(fa[i]);

在第一次经过递归找到某个节点的祖先后,直接将每个节点直接指向它的祖先,下次不需要再重复查询节点的祖先时,不需要再执行递归的重复步骤

//2、查询 (添加了路径压缩后) 
  int find(int i)//找i的祖先代表的元素 
  {
  	if(fa[i]==i)//递归出口,到达了祖先位置,就返回祖先
  	     return i;
    else 
	{
		fa[i]=find(fa[i]);//该步进行了路径压缩 
    	return fa[i]; //返回父节点 
	}  
   } 

下面来看例题

输入:
10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4
7 10
8 9

#include<cstdio>
#include<cstdlib>
using namespace std;
#define MAXN 20001
int fa[MAXN];
void init(int n)
{
	for(int i=1;i<=n;i++)//每个人都初始化设置自己为自己的亲戚 
	    fa[i]=i;
}
int find(int x)//压缩后的查找函数 
{
	if(x==fa[x]) //如果这个人和自己互为亲戚,则返回值为亲戚的编号 
	    return x;
	else
	{
		fa[x]=find(fa[x]);如果这个人和自己不互为亲戚,
		  //则递归继续查找,并且找到后,直接将这个人与找到的最终亲戚建立关系
		  //下次使用就不需要重复递归遍历 
		return fa[x];
	}
}
void unionn(int i,int j)//将两个人建立亲戚关系的函数 
{
	int i_fa =find(i);//i的最终亲戚 
	int j_fa =find(j); //j的最终亲戚 
	fa[i_fa]=j_fa;//将i的指向j 
}
int main()
{
	int n,m,x,y,q;
	scanf("%d",&n);//输入人数 n
	init(n);//初始化  
	scanf("%d",&m);//需要建立的关系次数m 
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);//声明谁和谁是亲戚关系 
		unionn(x,y);
	}
	scanf("%d",&q);//查询次数q 
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);//要查询两人的编号 
		if(find(x)==find(y))//判断两人是否为亲戚函数 
		   printf("YES\n");
		else
		   printf("NO\n");
	}
	return 0; 
}

 作者在b站学习b站视频:麦克老师讲算法笔记做的相关笔记,本篇博客仅为学习交流目的,如有侵犯作者权益,请私聊博客主。欢迎广大读者评论交流。谢谢

并查集原理精讲_哔哩哔哩_bilibili

典例实践_哔哩哔哩_bilibili

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值