并查集的作用:
1、将两个数字所在的两个集合合并
2、询问两个数是否在一个集合中
对于n个数字,首先他们在不同的集合里面
集合用红字标识用于区别
比如 5个数字 1 2 3 4 5
现在数字分别是 1 2 3 4 5
集合编号分别是 1 2 3 4 5
现在将数字1 2所在的1 2集合合并,将2-->1
现在数字分别是 1 2 3 4 5
集合编号分别是 1 1 3 4 5
此时 数字1 2的父节点都是 1
现在将数字3 4 所在的3 4集合合并,将4-->3
现在数字分别是 1 2 3 4 5
集合编号分别是 1 1 3 3 5
现在将数字 2 3 所在的1 3集合合并,将3-->1
现在数字分别是 1 2 3 4 5
集合编号分别是 1 1 1 1 5
若此时进行查找两个数值是否在一个集合内
现在数字分别是 1 2 3 4 5
集合编号分别是 1 1 1 1 5
查找 数字 2 3 那就是查找他们的编号,此时都是集合1,因此他们属于一个集合
代码核心:找数字的集合
首先: for(int i=0;i<n;i++)q[i]=i;
各个数字对应各个集合
q[x]是x的目前集合位置
int find(int x){//返回节点位置加压缩
if(q[x]!=x)q[x]=find(q[x]);
return q[x];
}
最后一定会找到一个点的q[x]==x,这点就是祖宗节点
q[x]是x的父节点,q[q[x]是x的爷节点,find(q[x])就是找爷节点的过程,一直找下去,直到找到最开始的位置,然后把这个位置(就是他的集合位置)给他的每一个后代,这样就完成了路径压缩,接下来找的话一次性就可以找到最开始的祖宗
合并代码:
q[find(a)]=find(b);看这个情况如何实现
原来数字分别是 1 2 3 4 5
集合编号分别是 1 2 3 4 5
现在数字1 2所在的1 2集合合并,将2-->1
现在数字分别是 1 2 3 4 5
集合编号分别是 1 1 3 4 5
此时a=2,b=1;
find(a)=2;
find(b)=1;
q[find(a)]是find(a)的父节点,让它的父节点是find(b)
这样q[2]=1;此时q[1]=1;他们在一个集合中了
查找:
if(find(a)==find(b)) 这是找到他们的祖宗节点,一样的话那么他们就在一个集合
不一样的话,说明他们不在一个集合中
完整代码:
参考洛谷P3367
//省略头文件和自变量定义
int find(int x){//返回节点位置加压缩
if(q[x]!=x)q[x]=find(q[x]);
return q[x];
}
int main() {
cin>>n>>m;
for(int i=0;i<n;i++)q[i]=i; //初始位置
while(m--){ //m次操作
int l;
cin>>l;//输入本次操作
cin>>a>>b;
if(l==1){ //合并
q[find(a)]=find(b);//返回father节点
}else{ //查找
if(find(a)==find(b)){
cout<<"Y"<<endl;
}else{
cout<<"N"<<endl;
}
}
}
return 0;
}