最小生成树
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
Prim算法简述
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:V
new= {x},其中x为集合V中的任一节点(起始点),E
new= {},为空;
3).重复下列操作,直到V
new= V:
a.在集合E中选取权值最小的边<u, v>,其中u为集合V
new中的元素,而v不在V
new集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
b.将v加入集合V
new中,将<u, v>边加入集合E
new中;
4).输出:使用集合V
new和E
new来描述所得到的最小生成树。
算法实现:
输入数据:
5 7
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
输出数据:
V1-V2=10
V1-V4=30
V4-V3=20
V3-V5=10
最小权值=70
V1-V4=30
V4-V3=20
V3-V5=10
最小权值=70
#include<iostream>
using namespace std;
#define MAX 100
#define MAX_DIS 1000000
int mat[MAX][MAX];
int prim(int mat[][MAX], int n) {
int lowcost[MAX];
int mst[MAX];
int min, minid = 0, sum = 0;
for (int i = 2; i <= n; i++) {
lowcost[i] = mat[1][i];
mst[i] = 1;
}
mst[1] = 0;
for (int i = 2; i <= n; i++) {
min = MAX_DIS;
for (int j = 2; j <= n; j++) {
if (lowcost[j] < min && lowcost[j] != 0) {
min = lowcost[j];
minid = j;
}
}
cout << "V" << mst[minid] << "-V" << minid << "=" << min << endl;
sum += min;
lowcost[minid] = 0;
for (int j = 2; j <= n; j++) {
if (mat[minid][j] < lowcost[j]) {
lowcost[j] = mat[minid][j];
mst[j] = minid;
}
}
}
return sum;
}
int main() {
int m, n;
int x, y, cost;
cin >> m >> n;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= m; j++) {
mat[i][j] = MAX_DIS;
}
}
for (int k = 1; k <= n; k++) {
cin >> x >> y >> cost;
mat[x][y] = mat[y][x] = cost;
}
cout << "最小权值=" << prim(mat, m) << endl;
system("pause");
return 0;
}