本文通过几道题介绍一下并查集的应用。
第一道题目:The Sus pects (http://acm.pku.edu.cn/JudgeOnline/problem?id=1611)
1. N个人编号,从0到N-1。
2. 给出这N个人分成M个集合的描述(同一个人可以加入不同的集合)。
求所有和0号有关系的集合的人数!
//用到并查集的3种基本操作
//并查集虽然用线性的数组,但是使用树 的操作。
#include <stdio.h>
int set[30001],i,j;
void MakeSet(int n)
//集合初始化为-1
//set[x]<0 表示x是根 并且它的所有结点的个数为该值的绝对值。
//初始可以看成,数组中每个元素是一个根,相互独立的集合。
{
for(i=0;i<n;i++)
set[i]=-1;
}
int FindSet(int a)
//查找含有a的集合的根
{
int i=a,t;
while(set[i]>=0) //递归查找直到找到根为止
i=set[i];
while(i!=a) //压缩路径,使得各个孩子直接指向根,以便下次搜索加速。
{
t=set[a];
set[a]=i;
a=t;
}
return i;
}
int UnionSet(int a,int b)
//合并含有a和b的集合。并返回合并后树的根
{
if(a==b)
return a;
if(set[a]>=set[b])
{
set[b]+=set[a]; //把2集合元素个数相加
set[a]=b; //把a的根设置为b
return b;
}
else
{
set[a]+=set[b]; //把2集合元素个数相加
set[b]=a; //把b的根设置为a
return a;
}
}
int main()
{
int number,a,b,n,m;
while(scanf("%d %d",&n,&m) && (n || m))
{
MakeSet(n);
for(i=0;i<m;i++)
{
scanf("%d",&number);
scanf("%d",&a);
a=FindSet(a); //找到第一个元素所在集合的根。
for(j=1;j<number;j++)
{
scanf("%d",&b);
b=FindSet(b); //找到这个元素b所在的集合
a=UnionSet(a,b); //把a和b合并,然后把合并后的根返回给a以便循环使用。
}
}
union find 算法 可用在聚类
最新推荐文章于 2024-09-30 21:44:06 发布
并查集(Union-Find Sets)
2009-02-23 12:38