并查集由一个整数型的数组和两个函数构成。数组pre[]记录了每个点的前导点是什么,函数find是查找,函数join是合并。
这张图反映了并查集的基本思路,每个人都有自己的上级,由等级最高的人(祖先)统领这些关系,由此构成了如图的一个个群落,可以将这n个人比作n个独立的点,而关系就是连接两个点之间的路径
并查集find()函数与join()函数的初始化
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
return r;
}
void join(int x,int y)将x的祖先变为y的祖先,将其强行拉入伙~~
{
int fx=finx(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
find()函数的优化——路径压缩
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
并查集应用——HDU1232
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int pre[1010];
int n,m;
int num;
void init()
{
for(int i=1;i<=n;i++)
pre[i]=i;
num=n-1;
}
int find(int x)
{
int r=x;
while(pre[r]!=r)
r=pre[r];
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
void join(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
{
pre[fx]=fy;
num--;
}
}
int main()
{
int a,b;
while(cin>>n&&n)
{
cin>>m;
init();
while(m--)
{
scanf("%d%d",&a,&b);
join(a,b);
}
cout<<num<<endl;
}
return 0;
}