图的最小生成树Prim算法朴素版(C++)

Prim算法从一个节点开始不断选择权值最小的边加入当前已有的树结构,最终遍历完所有的节点得到最小生成树。

时间复杂度为O(V^2)。V为图中顶点个数。

C++代码如下:

#include <iostream>
#include <vector>

using namespace std;

typedef int DATA_TYPE;  // 权值为int型
const DATA_TYPE NO_EDGE = 10000000;  // 表示没有该边

// 邻接矩阵
struct AdjMatrixGraph
{
    vector<vector<DATA_TYPE> > weights;
};

vector<vector<int> > Prim(AdjMatrixGraph graph, int startNode)
{
    vector<vector<int> > MST;   // 最小生成树边结果集合
    int vertexNum = graph.weights.size();
    DATA_TYPE minDistance;  // 权值最小值存储变量

    // 初始化
    // 对于未访问集合中的顶点i
    // crossDistance[i]为已访问集合中的某个顶点到未访问集合中的顶点i之间的最小权值
    // closet[i]为达到最小权值下的已访问集合的中的某个顶点k
    // 即crossDistance[i] = min(weights[.][i])
    // closet[i] = argmin_k(weights[k][i], k=1...vertexNum)
    vector<DATA_TYPE> crossDistance = graph.weights[startNode];
    vector<int> closet(vertexNum, startNode);

    int k;  // 最近顶点的编号

    for (size_t i = 1; i < vertexNum; ++i)
    {
        minDistance = NO_EDGE;
        for (size_t j = 0; j < vertexNum; ++j)
        {
            if (crossDistance[j] > 0 && crossDistance[j] < minDistance)
            {
                minDistance = crossDistance[j];
                k = j;
            }
        }
        MST.push_back(vector<int>{closet[k], k});  // 找到最小边 加入结果
        crossDistance[k] = 0;  // 加入顶点k到已访问集合

        // 更新crossDistance和closet
        for (size_t j = 0; j < vertexNum; ++j)
        {
            if (graph.weights[k][j] > 0 && graph.weights[k][j] < crossDistance[j])
            {
                crossDistance[j] = graph.weights[k][j];
                closet[j] = k;
            }
        }
    }

    return MST;
}

int main(int argc, char *argv[])
{
    // 图邻接矩阵
    // 编号从0开始 若不是先转换
    AdjMatrixGraph graph;
    graph.weights.push_back(vector<DATA_TYPE>{0, 6, 1, 5, NO_EDGE, NO_EDGE});
    graph.weights.push_back(vector<DATA_TYPE>{6, 0, 5, NO_EDGE, 3, NO_EDGE});
    graph.weights.push_back(vector<DATA_TYPE>{1, 5, 0, 5, 6, 4});
    graph.weights.push_back(vector<DATA_TYPE>{5, NO_EDGE, 5, 0, NO_EDGE, 2});
    graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, 3, 6, NO_EDGE, 0, 6});
    graph.weights.push_back(vector<DATA_TYPE>{NO_EDGE, NO_EDGE, 4, 2, 6, 0});

    vector<vector<int> > MST = Prim(graph, 0);

    for (size_t i = 0; i < MST.size(); ++i)
    {
        cout <<"边(" << MST[i][0] << " " << MST[i][1] << ")  ||  权值: " << graph.weights[MST[i][0]][MST[i][1]] << endl;
    }

    return 0;
}

测试用例图如下:

这里写图片描述

编译环境(CLion 2016 with MinGW G++, GDB 7.11)
输出结果:
边(0 2) || 权值: 1
边(2 5) || 权值: 4
边(5 3) || 权值: 2
边(2 1) || 权值: 5
边(1 4) || 权值: 3

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值