您的位置:首页 > 编程语言 > C语言/C++

最小生成树之普里姆(Prim)算法

2016-08-16 21:33 309 查看
Prim 算法是一种贪心算法(适合稠密图)

设G=(V, E) 是无向连通带权图,V={0, 1, 2, ..., n-1};设最小生成树 T=(U, E'),算法结束时 U=V,E'⊆E。

贪心选择的思想是:每次对于还未加入到 U 中(即 V-U 中)所有点顶,从这些顶点中选择一个顶点,选择的标准是,它距离 U 最近(和 U 中某个顶点的权值最小),将这个顶点加入到

U 中,并将这条边加入到 E' 中。当所有顶点都加入到了
U 中,算法结束。



C++代码:

#include <iostream>
#include <cassert>
#include <limits>

using namespace std;

/*
* n : 图的顶点个数
* u0:开始顶点
* C :带权邻接矩阵
*/
int prim(int n, int u0, int **C) {
assert(n > 0 && u0 >= 0 && u0 < n);

bool s
;// 用于标记顶点是否加入到了 U 中
int closest
;// closest[i],表示 V-U 中的一个顶点 i,在 U 中的最近邻接点 closest[i]
int lowcost
;// lowcost[i],表示 V-U 中的一个顶点 i,到 U 中所有顶点的最短边的权值,即边 <i, closest[i]> 的权值
s[u0] = true;// 初始点默认已加入到 U 中
for(int i=0; i < n; i++) {
if(i != u0) {
s[i] = false;// 初始化:其他所有的点都未加入到 U 中,都在 V-U 中
closest[i] = u0;// 初始化:其他所有点,在 U 中的最近邻近点,都是初始点
lowcost[i] = C[u0][i];// 因此,它们对应的和 U 中的最短边的权值即使与初始顶点的权值
}
}
const int INFINITY = numeric_limits<int>::max();
for(int i=0; i < n; i++) {// 在 V-U 中寻找距离 U 最近的顶点并更新 closest 和 lowcost
int minWeight = INFINITY;
int t = u0;
for(int j=0; j < n; j++) {// 在 V-U 中寻找距离 U 最近的顶点 t
if(!s[j] && lowcost[j]<minWeight) {
t = j;
minWeight = lowcost[j];
}
}
if(t == u0)// 因为 u0 在 U 中,如果在 V-U 中找到了,t 不可能为 u0,为 u0 表示没有找到
break;// 说明在 V-U 中没有顶点和 U 中的任何一个顶点相邻了,没有必要再在 V-U 中继续浪费时间了
s[t] = true;// 找到这个点后,将其加入到 U 中
for(int j=0; j < n; j++) {// 因为 U 中加入了新的顶点,可能需要更新 V-U 中所有点顶的 closest 和 lowcost
if(!s[j] && (C[t][j]<lowcost[j])) {
lowcost[j] = C[t][j];
closest[j] = t;
}
}
}
int cost = 0;
for(int i=0; i < n; i++) {
if(i != u0)
cost += lowcost[i];
}
return cost;
}

int main() {
int N;
cin >> N;
int **C = new int*
;
int minEdge = 0;
int u0 = 0;
for(int i=0; i < N; i++) {
C[i] = new int
;
for(int j=0; j < N; j++) {
cin >> C[i][j];
if(minEdge > C[i][j]) {
minEdge = C[i][j];
u0 = i;
}
}
}

cout << prim(N, u0, C) << endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息