并查集模板

博客围绕并查集展开,介绍了合并两个点时判断是否属于同一连通分量,若不属于则加入;还提及判断图中单独连通分量数量,以及将图压缩成最小生成树时判断点是否在树中。同时指出当链上点过多时标记顶点的问题,引出路径压缩方法。

1.合并2个点时,可以判断2个点是否属于一个联通分量,如果不属于,那么加入该连通分量,
2. 最后判断该图 有几个单独的联通分量,
3. 或者将图压缩成 最小生成树时,判断每个点是否属于最小生成树中,不是就加入树中,

  • 用一个pre[i]表示点i在图中的顶点,初始化时每个点i(都是一个单独的联通分量)所以顶点就是,判断联通分量的数量也是判断pre[i] == i
  • 合并两个u,v,一开始标记pre[u]=v pre[v]=u都行,说明他们是另一个的父亲节点,但是如果一条链上点多了,每个点的只能记录它的父亲节点,就没有达到标记图的顶点的目的,这是要用到一个叫做路径压缩的方法
  • 路径压缩,先找到点i的顶点,然后不断的将该条路上的点的父亲节点都设置成顶点,
重要的是路径压缩
#include<iostream> 
using namespace std;
const int maxn=1000+10;
int pre[maxn];//记录每一个点的前一个节点,(最后都变成该点的根节点)
int find(int x){//寻找点x的根节点
    int root=x;
    while( pre[root]!=root )//当前点的根节点不是自己
        root=pre[root];//一直向前找
    //路径压缩,所有点的前一个点都为根节点   减少时间复杂度
    while(pre[x]!=root){
        int k=pre[x];//当前点的前一个点暂时保存
        pre[x]=root;//当前点的前一个点为根节点
        x=k;//继续遍历当前点的前一个点
    }
    return root;
}
void merge(int a,int b){//将两点代表的连通分量连成一个连通分量
    if( find(a)!=find(b) ) //属于相同连通分量就不连,
        pre[find(a)]=find(b);//a的根节点的父亲可以使b根节点父亲,反之成立
}
int main(){
    int n,m;// n个节点,m条边。
    cin>>n>>m;
    for(int i=1;i<=n;i++)   pre[i]=i;
    for(int i=0;i<m;i++){
        int a,b;
        cin>>a>>b;
        merge(a,b);
    }
    //看有几个连通分量
    int ans=0;
    for(int i=1;i<=n;i++)//根节点代表自己就是一个独立的连通分量
        if( pre[i]==i )  ans++;
    cout<<ans;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值