当前位置: 首页 > news >正文

用Prim算法求解最小生成树:代码实现与分析

在图论的世界里,最小生成树(MST)问题是一个经典且重要的课题。今天,我们就来深入探讨使用Prim算法解决最小生成树问题,并对一段C++代码进行详细解读。

一、Prim算法简介

Prim算法是一种贪心算法,用于在加权无向连通图中找到一棵最小生成树。其核心思想是从图中的任意一个顶点开始,逐步扩展生成树,每次选择与当前生成树相连的边中权重最小的边,将对应的顶点加入生成树,直到所有顶点都被包含在生成树中。

二、代码解读

下面是实现Prim算法的C++代码:

#include<iostream>
#define int long long
#define N 10005
using namespace std;
int g[N][N];
int w[N], pr[N];
int n,m;
int sum;
void prime(){
    int j, mmin = 0x3f3f3f3f;
    for (int i = 2; i <= n; i++){
        w[i] = g[1][i];
        pr[i] = 0;
    }
    pr[1]=-1;
    for (int i = 2; i <= n; i++){
        mmin = 0x3f3f3f3f;
        int k = 0;
        for (int j = 1; j <= n; j++){
            if (pr[j]!=-1&&w[j] <= mmin){
                mmin = w[j];
                k = j;
            }
        }
        pr[k] = -1;
        for (int j = 1; j <= n; j++)
        {
            if (pr[j]!=-1&&w[j]>=g[k][j])
            {
                w[j] = g[k][j];
                pr[j] = k;
            }
        }

    }
}
signed main() {
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++)
        g[i][j]=0x3f3f3f3f;
    }
    while (m--){
        int x, y, c;
        cin >> x >> y >> c;
        if (c < g[x][y]) {
            g[x][y] = c;
            g[y][x] = c;
        }
    }
    prime();
    for (int i = 1; i <= n; i++){
        sum+=w[i];
    }
    if(sum>=0x3f3f3f3f/2){
        cout<<"impossible";
        return 0;
    }
    cout << sum << endl;
    return 0;
}

1. 变量定义

  • g[N][N]:二维数组,用于存储图的邻接矩阵,g[i][j]表示顶点i和顶点j之间的边的权重。
  • w[N]:数组,用于记录每个顶点到当前生成树的最小距离。
  • pr[N]:数组,用于记录每个顶点在最小生成树中的前驱节点。
  • n:表示图中顶点的数量。
  • m:表示图中边的数量。
  • sum:用于累加最小生成树的边的权重和。

2. prime函数

  • 初始化部分
for (int i = 2; i <= n; i++){
    w[i] = g[1][i];
    pr[i] = 0;
}
pr[1]=-1;

这部分代码从顶点2开始,将每个顶点到顶点1的距离初始化为g[1][i],并将顶点1的前驱节点设为-1,表示它是起始节点。

  • 核心循环部分
for (int i = 2; i <= n; i++){
    mmin = 0x3f3f3f3f;
    int k = 0;
    for (int j = 1; j <= n; j++){
        if (pr[j]!=-1&&w[j] <= mmin){
            mmin = w[j];
            k = j;
        }
    }
    pr[k] = -1;
    for (int j = 1; j <= n; j++)
    {
        if (pr[j]!=-1&&w[j]>=g[k][j])
        {
            w[j] = g[k][j];
            pr[j] = k;
        }
    }
}

外层循环从顶点2开始,每次找到距离当前生成树最近的顶点k。内层第一个循环遍历所有顶点,找到未被加入生成树(pr[j]!=-1)且距离最小的顶点k。然后将顶点k的前驱节点设为-1,表示它已被加入生成树。内层第二个循环更新其他未加入生成树的顶点到当前生成树的距离和前驱节点。

3. main函数

  • 初始化邻接矩阵
for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++)
    g[i][j]=0x3f3f3f3f;
}

将邻接矩阵的所有元素初始化为一个很大的值0x3f3f3f3f,表示初始时顶点之间没有边相连。

  • 读入边的信息
while (m--){
    int x, y, c;
    cin >> x >> y >> c;
    if (c < g[x][y]) {
        g[x][y] = c;
        g[y][x] = c;
    }
}

读入图的边的信息,包括两个顶点xy以及边的权重c。如果读入的边的权重小于当前邻接矩阵中对应位置的值,则更新邻接矩阵。

  • 调用prime函数并计算结果
prime();
for (int i = 1; i <= n; i++){
    sum+=w[i];
}
if(sum>=0x3f3f3f3f/2){
    cout<<"impossible";
    return 0;
}
cout << sum << endl;

调用prime函数计算最小生成树,然后累加w数组中的值得到最小生成树的权重和sum。如果sum大于等于一个很大的值的一半(这里用0x3f3f3f3f/2判断),说明图不连通,无法计算最小生成树,输出impossible;否则输出最小生成树的权重和。

三、总结

这段代码通过Prim算法实现了求解最小生成树的功能。在理解和编写这类代码时,关键在于清晰地把握Prim算法的核心思想,即如何逐步扩展生成树,以及如何正确地更新顶点到生成树的距离和前驱节点。同时,对图的初始化、边的读入和结果的判断与输出等细节也需要仔细处理。希望通过这篇博客,能帮助大家更好地理解Prim算法及其在C++中的实现。

相关文章:

  • AIGC(生成式AI)试用 21 -- Python调用deepseek API
  • 多线程之两阶段终止模式
  • 【DeepSeek】本地部署,保姆级教程
  • scala中为什么能用常量的地方就不用变量
  • Miniconda + VSCode 的Python环境搭建
  • 解锁观察者模式:Java编程中的高效事件管理之道
  • 【Windows软件 - HeidiSQL】导出数据库
  • golang常用库之-swaggo/swag根据注释生成接口文档
  • halcon 条形码、二维码识别、opencv识别
  • Java零基础入门笔记:(4)方法
  • 每日一题——将数字字符串转化为IP地址
  • 深入解析 iOS 视频录制(三):完整录制流程的实现与整合
  • 如何连接别人的redis服务器吗?
  • 嵌入式八股文(四)计算机网络篇
  • selenium环境搭建
  • 【故障处理】- 11G expdp导出缓慢 + Streams AQ: enqueue blocked on low memory等待事件
  • mybatis 批量提交-提升效率
  • P11071 「QMSOI R1」 Distorted Fate Solution
  • C# 使用 CSRedis 来操作 Redis 队列
  • ART光学跟踪系统在汽车制造与设计审核中的实际应用
  • 西域都护府博物馆今日在新疆轮台县开馆
  • 重庆城市轨道交通拟听证调价:公布两套票价方案,正征求意见
  • “GoFun出行”订单时隔7年扣费后续:平台将退费,双方已和解
  • 美联储官员:美国经济增速可能放缓,现行关税政策仍将导致物价上涨
  • 俄乌直接谈判结束,乌称“毫无成果”
  • 马上评|让查重回归促进学术规范的本意