基本原理:每个集合用一颗树来表示,树根的编号就是整个集合的编号,每个节点存储他的父节点编号,p[x]表示x的父节点编号
两个基本操作
find操作:询问两个元素是否属于一个集合
merge操作:合并两个集合
首先,初始化p数组,一开始每一个元素都是一个集合,即每个元素的父节点都是自己
for(int i=0;i<=n;i++)p[i]=i;//每个元素都是一个集合
随后,读取元素进行上述基本操作
find操作
定义find函数返回所查询元素的父亲结点
int find(int x)//返回x的祖宗节点
{
return find(p[x]);
}
此时可以进一步进行优化将每个子节点都指向父节点进行路径压缩,大大降低时间复杂度
int find(int x)//返回x的祖宗节点+路径压缩
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
merge操作
合并a,b两个元素所在集合
void merge(int a,int b)
{
p[find(a)]=find(b);
}
代码解释:将a的父亲结点赋值为b的父亲结点,也就是将a集合合并到b集合,将a的根节点接到b的根节点上
全代码:
#include<iostream>
using namespace std;
const int N=100100;
int n,m;
int p[N];
int find(int x)//返回x的祖宗节点+路径压缩
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
void merge(int a,int b)//合并操作
{
p[find(a)]=find(b);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++)p[i]=i;//每个元素都是一个集合
while(m--)
{
char op[2];//读取操作
int a,b;//读取元素
scanf("%s%d%d",op,&a,&b);
if(op[0]=='M')merge(a,b);
else
{
if(find(a)==find(b))puts("Yes");
else puts("No");
}
}
return 0;
}
658

被折叠的 条评论
为什么被折叠?



