并查集主要运用于一些带有连带关系的题目。
比如说,A是B的朋友,B是C的朋友。那么A是C的朋友。给你一系列的人,和这些人之间的关系。
然后让你求一共有多少个关系,或者A,B之间是否存在关系。
也可运用于一些点,求最少需要几个边才能形成一张连通图~
运用步骤:
初始化
把每个点所在集合初始化为其自身。 通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。查找
查找元素所在的集合,即根节点。合并
将两个元素所在的集合合并为一个集合。 通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。样例分析:
HUD1232
#include<stdio.h>
int town[1001];
int get(int x)
{
while(town[x]!=x)
x=town[x];
return x;
}
void pan(int x,int y)
{
x=get(x);
y=get(y);
if(x!=y)
{
town[y]=x;
}
}
int main()
{
int sum,i,m,n,a,b;
while(scanf("%d",&n)&&n)
{
scanf("%d",&m);
for(i=1;i<=n;i++)
{
town[i]=i;
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
pan(a,b);
}
sum=0;
for(i=1;i<=n;i++)
{
if(town[i]==i)
sum++;
}
printf("%d\n",sum-1);
}
return 0;
}
HDU 1272
#include<stdio.h>
int point[200000];
int sum[200000];
int leap;
int get(int x)
{
while(point[x]!=x)
x=point[x];
return x;
}
void pan(int x,int y)
{
x=get(x);
y=get(y);
if(x==y)
leap=1;
else
{
point[y]=x;
}
}
int main()
{
int m,n,i,leapp;
while(scanf("%d%d",&n,&m)&&((n+1)||m+1))
{
leap=0;
for(i=0;i<=100000;i++)point[i]=i,sum[i]=0;
sum[n]=1;
sum[m]=1;
if(m||n)pan(n,m);
else
{
printf("Yes\n");
continue;
}
while(scanf("%d%d",&n,&m)&&(n||m))
{
pan(n,m);
sum[n]=1;
sum[m]=1;
}
leapp=0;
for(i=1;i<=100000;i++)
{
if(sum[i]==1&&point[i]==i)
leapp++;
}
if(leapp==1&&leap==0)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
POJ 1611
#include<stdio.h>
int point[50000];
int find(int x)
{
while(point[x]!=x)
x=point[x];
return x;
}
void pan(int x,int y)
{
x=find(x);
y=find(y);
if(x!=0&&y!=0)
{
if(x!=y)
{
point[y]=x;
}
}
else if(x==0&&x!=y)
{
point[y]=x;
}
else if(y==0&&x!=y)
{
point[x]=y;
}
}
int main()
{
int leap,m,n,i,a,b,c,j;
while(scanf("%d%d",&n,&m)&&(m||n))
{
for(i=0;i<n;i++)
{
point[i]=i;
}
for(i=0;i<m;i++)
{
scanf("%d",&a);
scanf("%d",&b);
for(j=1;j<a;j++)
{
scanf("%d",&c);
pan(b,c);
}
}
leap=0;
for(i=0;i<n;i++)
{
if(find(i)==0)
leap++;
}
printf("%d\n",leap);
}
return 0;
}