并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其特点是看似并不复杂,但数据量极大并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。常常在使用中以森林来表示。
并查集通常包含两个常用的函数 : find() 和 join() ,find()函数是用来查看某个体祖先的,join()函数是将两个 个体的祖先联系在一起。这里再提一下路径压缩,因为我们在看两个体是否具有某种关系时只需查看他们是否有共同的祖先即可,所以我们在join()函数中,在查找某个体的祖先时将其路径上的所有个体均直接指向其祖先,那么在查找时会方便很多。
看例题(HDUOJ-1856-More is better):
问题描述:
说 Mr Wang 需要学生来帮他完成一个工程,学生的个数越多越好,当然选择学生是有前提的,那就是选择的学生必须间接或直接为朋友关系,这时他找了间足够大的房子里面有1000 000 个学生,经过他的挑选未被选择的学生将离开房子,请你帮他选择出最多能选择多少学生(至少为一个)。
输入:第一行为关系是直接朋友的学生对数 n ( 0 =< n <= 10 0000),然后包含n行每行为一对学生A,B(1<=A,B<=1000 000);
输出:输出最多能选取的学生个数。
代码奉上:
#include<stdio.h>
#include<string.h>
int pre[1000000]; //并查集用来储存学生间的朋友关系(即具有共同祖先的个体为朋友关系)
int sum[1000000]; //记录每个个体有多少个朋友
int max = 0; //记录个体拥有朋友最多的数量
int find(int x){ //查找祖先的函数
if (pre[x]==x)
return x;
pre[x] = find(pre[x]);//这里为路径压缩,将每一个个体的父亲直接设为祖先
return pre[x];
}
void join(int x,int y){//链接函数,将两个体的祖先联系起来
int fx = find(x);
int fy = find(y);
if (fx==fy)
return ;
pre[fx] = fy;
sum[fy] += sum[fx]; //将个体拥有朋友的数量合并
max = max<sum[fy]?sum[fy]:max; //寻找最大值
}
int main (){
int n,a,b,i;
while (scanf("%d",&n) != EOF){
for (i=0;i<=2*n;i++){//初始化,一开设定,每个学生都没有朋友,即sum = 1;
pre[i] = i;
sum[i] = 1;
}
for (i=0;i<n;i++){
scanf("%d%d",&a,&b);
join(a,b);//将具有朋友关系的学生合并
}
printf("%d\n",max);
max = 1; 初始化max进行下一轮数据的测试
}
}