基于路径压缩的并查集可以在更短的时间内几何元素的查找和合并。
每次集合元素合并之前遍历集合(森林实现),在遍历时将路径进行压缩
“
while(person[i].parent!=i)
{
person[i].parent=person[person[i].parent].parent;
i=person[i].parent;
}
”
这样在集合数逐渐减少,节点数逐渐增加时,森林的深度不会太大。因此对于每次元素的查找时间不会很大。
在合并时,只需判断两个集合的元素数目个数,将元素数目少的集合归并到元素多的集合上(本来是判断森林深度的)。
“
if(i!=j)
{
if(person[i].nodenum>person[j].nodenum)
{
person[j].parent=i;
person[i].nodenum+=person[j].nodenum;
sum--;
}
else
{
person[i].parent=j;
person[j].nodenum+=person[i].nodenum;
sum--;
}
}
”
EG:对于n个人,输入m组关系(a,b),表示a和b有关系,并且关系具有传递性。判断n个人中最多有多少个社区?
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
#define max 100000
struct{
int parent;
int nodenum;
}person[max];
int sum=max;
//集合查找和合并
void merge(int fir,int sec)
{
int i=fir,j=sec;
while(person[i].parent!=i)
{
person[i].parent=person[person[i].parent].parent;
i=person[i].parent;
}
while(person[j].parent!=j)
{
person[j].parent=person[person[j].parent].parent;
j=person[j].parent;
}
if(i!=j)
{
if(person[i].nodenum>person[j].nodenum)
{
person[j].parent=i;
person[i].nodenum+=person[j].nodenum;
sum--;
}
else
{
person[i].parent=j;
person[j].nodenum+=person[i].nodenum;
sum--;
}
}
}
int main()
{
int n,m;
int first,second;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++)
person[i].parent=i,person[i].nodenum=1;
sum=n;
for(int i=0;i<m;i++)
{
scanf("%d%d",&first,&second);
merge(first,second);
}
printf("%d\n",sum);
}
return 0;
}