0
点赞
收藏
分享

微信扫一扫

并查集的实现

树下的老石头 2022-01-25 阅读 98

并查集的作用:

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;
}
 

举报

相关推荐

0 条评论