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