并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。
操作步骤:
1.初始化:把每个节点初始化为自身。(即自身为自身的根节点)
2.查找:查找元素所在的集合。(即根节点)
3.合并:将两个元素所在的集合并成同一个集合。(即连接根节点)
简单例题:
(此题主要难点在于判断是否成环,若为环,则输出NO)
/*hdu--小希的迷宫*/
#include<stdio.h>
#include<string.h>
#define M 110000
int per[M];
int mark[M];
int flag;
int find(int x)
{
int r,i,j;
r=x;
while(r!=per[r])
r=per[r];
i=x;
while(i!=r)
{
j=per[i];
per[i]=r;
i=j;
}
return r;
}
void join(int x,int y)
{
int fx,fy;
fx=find(x);
fy=find(y);
if(fx!=fy)
per[fx]=fy;
else
flag=0;
}
void chu()
{
int i;
for(i=1;i<=100000;i++)
per[i]=i;
}
int main()
{
int n,m,x,y,i,sum;
while(scanf("%d %d",&n,&m))
{
memset(mark,0,sizeof(mark));
if(n==-1&&m==-1)break;
if(n==0&&m==0)
{
printf("Yes\n");
continue;
}
chu();
mark[n]=1;mark[m]=1;
join(n,m);
flag=1;sum=0;
while(scanf("%d %d",&n,&m))
{
if(n==0&&m==0)break;
mark[n]=1;
mark[m]=1;
join(n,m);
}
for(i=1;i<=100000;i++)
{
if(per[i]==i&&mark[i])
sum++;
if(sum>1)
{
flag=0;
break;
}
}
if(flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}
(此题可以看成寻找一个含有最多元素的集合,求出元素个数)
/*
hdu--more is better
注意 n (0 ≤ n ≤ 100 000),那么当n=0时,虽然没有朋友关系,但是会有一个人留下来*/
#include<stdio.h>
#define M 10000000
using namespace std;
int per[M];
int ran[M];
int max;
void chu()
{
int i;
for(i=1;i<=10000000;i++)
{
per[i]=i;
ran[i]=1;
}
}
int find(int x)
{
int r,i,j;
r=x;
while(r!=per[r])
r=per[r];
i=x;
while(i!=r)
{
j=per[i];
per[i]=r;
i=j;
}
return r;
}
void join(int x,int y)
{
int fx,fy;
fx=find(x);
fy=find(y);
if(fx!=fy)//当fx==fy是,则说明形成环,此时就不需要处理,不然会多加人数
{
per[fx]=fy;
ran[fy]+=ran[fx];//两个不同的根节点,把一个根节点的长度加到另一个根节点上
if(max<ran[fy])max=ran[fy];//比较每一个根节点的长度,保留较长的;
}
}
int main()
{
int i,a,b,t;
while(scanf("%d",&t)!=EOF)
{
if(t==0)
{
printf("1\n");
continue;
}
chu();
max=0;
for(i=1;i<=t;i++)
{
scanf("%d %d",&a,&b);
join(a,b);
}
printf("%d\n",max);
}
return 0;
}