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