并查集(Union Find)

并查集(Union Find)

准备工作

可以先看这个 超有爱的并查集~
解释的非常生动形象 tql

正文

oj用的是洛谷 P3367 【模板】并查集
优化有两种方式:

  1. 路径压缩(常用)
  2. 按秩合并

路径压缩

#include <bits/stdc++.h>
using namespace std;
int n,m;
int pre[10005]; //父节点
int find(int r){
    if(r==pre[r]) return r; //根节点的pre是自己
    return pre[r]=find(pre[r]); //①路径压缩
}
int main(){
    cin>>n>>m;
    for(int i=0;i<=n;++i) pre[i]=i;
    int zi,xi,yi,r1,r2;
    while(m--){
        cin>>zi>>xi>>yi;
        r1=find(xi);
        r2=find(yi);
        if(zi==1){ //普通合并 
            if(r1!=r2) pre[r1]=r2; //xi所在的树合并到yi所在树
        }
        else{ //判断是否在一个并查集
            if(r1!=r2) cout<<"N\n";
            else cout<<"Y\n";
        }
    }
    return 0;
}

按秩合并

#include <bits/stdc++.h>
using namespace std;
int n,m;
int pre[10005]; //父节点
int ran[10005]; //秩(树高)
int find(int r){
    if(r==pre[r]) return r;
    return pre[r]=find(pre[r]); //①路径压缩
}
int main(){
    cin>>n>>m;
    for(int i=0;i<=n;++i) {pre[i]=i; ran[i]=1;}
    int zi,xi,yi,r1,r2;
    while(m--){
        cin>>zi>>xi>>yi;
        r1=find(xi);
        r2=find(yi);
        if(zi==1){ //②按秩合并 
            if(r1!=r2){ //将高度小的树合并到高度大的树上
                if(ran[r1]<ran[r2]) //r1->r2
                    pre[r1]=r2;
                else{ //r2->r1
                    if(ran[r1]==ran[r2]) ++ran[r1]; //相等合并时树高+1
                    pre[r2]=r1;
                }
            }
        }
        else{
            if(r1!=r2) cout<<"N\n";
            else cout<<"Y\n";
        }
    }
    return 0;
}
posted @ 2019-05-29 15:13  lidasu  阅读(307)  评论(0编辑  收藏  举报