并查集的简单操作
个人感觉并查集就是一个找爹的感觉,要把同一类的祖先找齐,就是寻找到是一个家族的人,又是可能某些数据被该家族踢出,但是实质上还是对数组下标的操作。
1.最普通的并查集操作
例题:HDU1213
问题:就是问认识的人可以坐在一起,问最少需要多少个桌子,这些人可以全都坐下
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int f[1010]={0},n,m;
void init(){
for(int i=1;i<=n;i++)
f[i]=i;
}
int find(int v){
if(f[v]==v)//如果现在的祖先还是他自己那么久直接返回
return f[v];
else{
f[v]=find(f[v]);//如果他的祖先不是自己了,就要通过递归一步一步的向上找到自己的祖先节点,并返回祖先节点的下标
return f[v];
}
}
void merge(int v,int u){
int t1,t2;
t1=find(v);
t2=find(u);
if(t1!=t2)
f[t2]=t1;//其实这就是个认爹的过程,有关系的下标就要弄成相同的
return ;
}
int main(){
int h,x,y;
scanf("%d",&h);
for(int i=1;i<=h;i++){
scanf("%d %d",&n,&m);
init();//首先定义一下,让每一个数据的父亲节点先指向自己
for(int j=1;j<=m;j++){
scanf("%d %d",&x,&y);
merge(x,y);//开始找爹,把有关系的下标全都赋值成最后的祖先的下标
}
int sum=0;
for(int j=1;j<=n;j++)
if(f[j]==j)//最后遍历一遍所有数组数据所记录的下标,下标相同的就是可以坐在同一个桌子上的,最后的结果就是最少需要的桌子的数量。
sum++;
printf("%d\n",sum);
}
return 0;
}
这里其实重要的记忆点就是两个函数,即find函数和merge函数
find函数
找祖先的过程
int find(int v){
if(f[v]==v)//如果现在的祖先还是他自己那么久直接返回
return f[v];
else{
f[v]=find(f[v]);//如果他的祖先不是自己了,就要通过递归一步一步的向上找到自己的祖先节点,并返回祖先节点的下标
return f[v];
}
}
merge函数
合并统一祖先的单元,形成一个整体
void merge(int v,int u){
int t1,t2;
t1=find(v);
t2=find(u);
if(t1!=t2)
f[t2]=t1;//其实这就是个认爹的过程,有关系的下标就要弄成相同的
return ;
}