假设G=(V,E)是一个具有n个顶点的带权无向连通图,T(U,TE)是G的最小生成树,其中U是T的顶点集,TE是T的边集,则构造G的最小生成树T的步骤如下:
/*==================================================*\
| Prim求最小生成树
| INIT: cost[][]耗费矩阵(inf为无穷大);
| CALL: prim(cost, n); 返回-1代表原图不连通;
\*==================================================*/
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_WEIGHT = 10000000;
const int MAX_NUM = 100;
int weight[MAX_NUM][MAX_NUM]; /* 存储权值的二维数组 */
int low[MAX_NUM]; /* low数组记录(V-U)中每个顶点到U点集的最小权值*/
bool U[MAX_NUM]; /* 判断是否已经存入点到集合 */
int prim(int n)
{
int ret = 0;
/* 从某点开始,分别标记和记录该点*/
U[0] = true;
int u = 0;
/* 第一次通过初始点u到每个点的权值给low赋值*/
for(int i = 0; i < n; i++) {
if(i != u)
low[i] = weight[u][i];
}
/* 再运行n-1次 */
for(int i = 0; i < n-1; i++) {
/* 从(V-U)找出最小权值并记录位置 */
int min = MAX_WEIGHT;
for(int j = 0; j < n; j++) {
if(!U[j] && min > low[j]) {
min = low[j];
u = j;
}
}
/* 叠加min到结果值ret中,此处即为TE的生成过程,如果想要知道详细路径可以在此记录 */
ret += min;
/* 将u加入到点集U中 */
U[u] = true;
/* 通过新加入到点集U中的点u更新数组low,只更新(V-U)中的顶点对应的low值*/
for(int j = 0; j < n; j++) {
if(!U[j]&& low[j] > weight[u][j])
low[j] = weight[u][j];
}
}
return ret;
}
int main()
{
memset(U, 0, sizeof(U));
memset(low, 0, sizeof(low));
memset(weight, 0, sizeof(weight));
int N; /* 顶点数*/
int E; /*边数*/
cin >> N;
cin >> E;
for (int i = 0; i < E; ++i) {
int v1, v2;
cin >> v1;
cin >> v2;
cin >> weight[v1][v2];
weight[v2][v1] = weight[v1][v2];
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (weight[i][j] == 0)
weight[i][j] = MAX_WEIGHT;
}
}
for (int i = 0; i < N; i++)
low[i] = MAX_WEIGHT;
cout << prim(N) << endl;
return 0;
}