并查集就是最开始又N个集合,这N个集合当中有一部分集合存在关联,就可以把有关联的集合合并在一起,这个关联也可以间接建立,所以要查找是否间接存在关联,最后得出剩余的集合数。
题目描述
有n个人,编号1-n。
现在有一个舞会,在舞会上,大家会相互介绍自己的朋友。
即: 如果a认识b,b认识c。那么在舞会上,a就会通过b认识到c。
现在,给出m个关系
每个关系描述:
a b
表示 编号为a和编号为b的人是朋友关系。
输入格式
输入n和m
接下来m行,每行为a b
输出格式
最后问,会有多少个朋友圈。
样例输入
5 3
1 2
2 3
4 5
样例输出
2
步骤:
初始化
先建立一个数组,用数组下标表示集合。
void fun(int n)
{
for(int i=1; i<=n; i++)
p[i]=i;
}
查找
因为每个集合最开始的值就是下标,代表还没有合并。当输入1 2时,说明1和2集合要合并为同一个集合。方法就是把p[1]的值由1变成2,也就是现在1和2就同属于一个集合里面。随后输入2 3。同理把p[2]的值变成3。集合又减少一个。
这一步通过find函数来实现。
b1=find(p1);
b2=find(p2);
if(b1!=b2)
{
p[b1]=b2;
}
int find(int x)
{
while(x!=p[x])
{
x=p[x];
}
return(x);
}
路径压缩
如果在输入了1 2,2 3,在输入1 3,也就是都通过2间接认识的时候,时会导致查找的时候变得很乱很复杂,解决的办法就是,路径压缩,把所有同属于一个集合的值变成同一个值。这一步直接加在find函数里面。
int find(int x)
{
int temp,n=x;
while(x!=p[x])
{
x=p[x];
}
while(n!=x)//路径压缩
{
temp=p[n];
p[n]=x;
n=temp;
}
return(x);
}
得出结果
根据上面的步骤可以看出,想求合并后剩余的集合只要判断数组值与下标是否相等就可以了。如果相等说明没有被合并。
int ans=0;
for(i=1;i<=n;i++)
if(p[i]==i)
ans++;
printf("%d\n",ans);
来源:CSDN
作者:Josephu.
链接:https://blog.csdn.net/m0_46193982/article/details/104077223