1. 介绍
并查集(union-find sets)是一种不相交集合,可用树表示。
union的加权规则:在两个树合并(union操作)时,以结点数多的树的root为新树的root;即结点数少的树接在结点数多的树上。
find的压缩规则:在find(x)操作时,沿节点x的parent链域走动,依次将parent链域的结点挂在root下。
2. 问题
2.1 POJ 1611
问题:求包含0元素的集合的结点数。
源代码
#include "stdio.h"
#include "string.h"
int parent[30000];
int find(int x)
{
int root,tail,temp;
if(parent[x]<0)
return x;
else
{
for(root=x;parent[root]>=0;root=parent[root]);
for(tail=x;tail!=root;tail=temp)
{
temp=parent[tail];
parent[tail]=root;
}
return root;
}
}
void root_union(int x,int y)
{
int xroot=find(x);
int yroot=find(y);
if(xroot!=yroot)
{
int temp=parent[xroot]+parent[yroot];
if(parent[xroot]<parent[yroot])
{
parent[yroot]=xroot;
parent[xroot]=temp;
}
else
{
parent[xroot]=yroot;
parent[yroot]=temp;
}
}
}
int main()
{
int n,m,k,x,y;
while(scanf("%d%d",&n,&m)&&(m!=0||n!=0))
{
memset(parent,-1,n*sizeof(int));
while(m--)
{
scanf("%d%d",&k,&x);
for(k=k-1;k>=1;k--)
{
scanf("%d",&y);
root_union(x,y);
}
}
printf("%d\n",-parent[find(0)]);
}
return 0;
}
2.2 POJ 2524
问题:所有不相交集合的个数
源代码
#include "stdio.h"
#include "string.h"
int parent[50000];
int find(int x)
{
int root,tail,temp;
if(parent[x]<0)
return x;
else
{
for(root=x;parent[root]>=0;root=parent[root]);
for(tail=x;tail!=root;tail=temp)
{
temp=parent[tail];
parent[tail]=root;
}
return root;
}
}
void root_union(int x,int y)
{
int xroot=find(x);
int yroot=find(y);
if(xroot!=yroot)
{
int temp=parent[xroot]+parent[yroot];
if(parent[xroot]<parent[yroot])
{
parent[yroot]=xroot;
parent[xroot]=temp;
}
else
{
parent[xroot]=yroot;
parent[yroot]=temp;
}
}
}
int main()
{
int n,m,x,y,i,count,case_num=1;
while(scanf("%d%d",&n,&m)&&(m!=0||n!=0))
{
memset(parent,-1,n*sizeof(int));
count=0;
while(m--)
{
scanf("%d%d",&x,&y);
root_union(x,y);
}
for(i=0;i<n;i++)
{
if(parent[i]<0)
count++;
}
printf("Case %d: %d\n",case_num,count);
case_num++;
}
return 0;
}