AcWing 858. Prim算法求最小生成树

本文详细解析了Prim算法在求解最小生成树问题中的应用,通过实例讲解了算法的基本思想与步骤,包括如何初始化距离数组,进行多次迭代操作找到最近点并更新距离,直至构建出最小生成树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:AcWing 858. Prim算法求最小生成树

题意

使用prim算法找出包含所有点的却只有n-1条边的无向连通子图, 并求出子图的最小权值。

分析

此题是非常裸的prim算法题,直接套用模板就ok了,但是一定要理解思想是怎样的。

思想

将图分为两个集合,其中一个集合是最小生成树(一开始是空集),另一个集合是不属于最小生成树的点集S,每次都找离最小生成树最近的点,并把这个点加入最小生成树,然后利用刚增加的点去更新 其它点到最小生成树的距离
这里定义一个数组d,d[i]的含义是从点i到集合S的最短距离
在这里插入图片描述
在这里插入图片描述

解决方案:

      1.输入点数和边数,初始化邻接矩阵和距离数组(定义为某个点到最小生成树集合的最短距离),输入边权(如果有重边,则取边权最小的边存储)
      2.进行n次操作,每次操作都会找到一个距离集合S最近的点,如果在某一次操作中找不到这个点,则说明这个图不连通,则这个图没有最小生成树
      3.随机抽取一个点(一般默认1号点),以这个点作为集合的第一个点,则这个点到集合的距离为0
      4.每次找到一个新点加入集合S,就用这个新点去更新其它点到集合S的距离

代码

#include <iostream>
#include <cstring>

using namespace std;

const int N = 510, INF = 0x3f3f3f3f;

//d数组定义为某个点到集合S的最短距离,g数组是邻接矩阵,n是点数,m是边数,ans是最小生成树的所有边权之和
int d[N], g[N][N], n, m, ans; 
//st数组定义为某个点到集合S的最短距离是否已经确定,如果确定了,则为true
bool st[N];

void prim() {
    memset(d, INF, sizeof d);   //一开始d[1]也是无穷大
    
    //遍历n次,每一次操作都会找到一个点加入集合S(如果图是连通的)
    for (int i = 0; i < n; i++) {
        int t = -1;
        for (int j = 1; j <= n; j++) 
            if (!st[j] && (t == -1 || d[j] < d[t]))
            t = j;
            
        //因为第一次操作时所有点到集合S的最短距离都是无穷大,所以第一次操作就不需要判断是否为无穷大    
        if (i && d[t] == INF) {  
            puts("impossible");
            return;
        }
        
        //将新点标记为已经找到最短距离
        st[t] = 1;
        
        //第一次操作不需要记录边权
        if (i) ans += d[t];
        
        //每次找到一个符合条件的新点,就用这个点更新集合S到其它点的最短距离
        for (int j = 1; j <= n; j++)
            d[j] = min(d[j], g[t][j]);
    }
    cout << ans;
}

int main() {
    memset(g, INF, sizeof g);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        g[a][b] = g[b][a] = min(g[a][b], c);  //输入边权,如果有重边则选择边权最小的边
    }
    prim();
    return 0;
}

总结

感觉prim算法本质就是每次去找两个集合之间的最短距离

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值