最小生成树 Prim & kruskal

最小生成树

给定一个图 G 用 n-1条边将点连起来,得到一颗边权之和最小的树。

最小生成树有两种算法,用哪种取决于 n,m 大小,边比较稀疏用 kruskal 完全图或者稠密图用Prim

Prim算法

将图中的点分为两个集合G1 G2一个表示在生成树中的点,一个表示不在生成树的点。

开始所有点都在 G2 任选一个起点s加入G1 记录一个dis数组表示G2 中的点到G1 中的点的边权最小值,每次选dis值最小的点加入G1,直到得到生成树。

复杂度 O(n^2)

inline void Prim(){
    memset(dis,0x3f3f3f,sizeof(dis));
    int tot = 0;//tot记录生成树边权之和
    vis[s] = 1;//vis 记录是否在G1中
    dis[1] = 0;
    int mini,k;
    for(int i=1;i<=n;++i)dis[i] = f[s][i]; // 边权,若没有则是正无穷
    for(int i=1;i<n;++i){
        mini = 0x3f3f3f;
        k = 0;
        for(int j=1;j<=n;++j){//找到dis最小的点 
            if(!vis[j] && dis[j] < mini){
                mini = dis[j];
                k = j;
            }
        }
        tot += dis[k];
        vis[k] = 1;
        for(int j=1;j<=n;++j)
            if(f[k][j] < dis[j])
                dis[j] = f[k][j];//更新边权最小值 
    } 
}

Kruskal算法

该算法复杂度为O(mlogm) m为边数

 实现也比较简单好理解:

将边按照边权升序排列,每次取出权值最小的边,如果边的端点不在同一颗树就插入生成树,反之舍弃,直到插入n-1条边。

是否在同一颗树用并查集维护。

inline int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}
inline void kruskal(){
    sort(g1+1,g1+1+m);//边权升序
    for(int i=1;i<=n;++i)f[i] = i;
    for(int i=1;i<=m;++i){
        int x = find(g1[i].x),y = find(g1[i].y);
        if(x == y)continue;
        f[x] = f[y];
        add(g1[i].x,g1[i].y,g1[i].dis);
        add(g1[i].y,g1[i].x,g1[i].dis);//建树
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值