图论 (五) 最小生成树算法【Prim算法】
最小生成树( ,简称):构造连通网的最小代价生成树
找连通网的最小生成树,经典的有两种算法,普里姆算法和克鲁斯卡尔算法。
Prim算法
大致思想:设图顶点集合为,首先任意选择图中的一点作为起始点,将该点加入集合,再从集合中找到另一点使得点到中任意一点的权值最小,此时将点也加入集合;以此类推,现在的集合,再从集合中找到另一点使得点到中任意一点的权值最小,此时将点加入集合,直至所有顶点全部被加入,此时就构建出了一颗。因为有个顶点,所以该就有条边,每一次向集合中加入一个点,就意味着找到一条的边。
图解
下面以图解的形式来说明算法的思想:
(1) 首先,顶点集合 = {},然后选定一点(这里选择点)加入集合,即 = {}, 寻找与相邻的所有边:
(2) 此时 = {}, = {},相邻的边有、,将加入最小生成树,同时将权值更小的边的顶点加入集合,此时 = {}
(3) 寻找中顶点与中顶点的所有边,如下图所示:
(4) 寻找权值最小的一条边的顶点加入,此时 = {}
(6) 如此反复循环,直到,最终结果如下:
算法实现
在这里我们采用邻接矩阵的方式来实现
以上述图解示例做出如下结构:
#define MAXVEX 100 //最大顶点数
#define INFINITY 65535 //代替无穷
int graph[MAXVEX][MAXVEX]; //图
char map[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i' }; //对应的顶点的描述
Prim算法的描述:
:表示以i为终点的边的最小权值,当说明以为终点的边的最小权值,也就是表示点加入了
:表示对应的起点,即说明边是的一条边,当表示起点加入,表示权值小的顶点下标
int Prim(int graph[][MAXVEX], int n) {
int i, j, k, min, sum = 0;
int adjvex[MAXVEX];
int lowcost[MAXVEX];
//从下标为0的顶点开始,即从a开始
lowcost[0] = 0;
//初始化第一个顶点下标为0
adjvex[0] = 0;
//循环下标除0外的所有顶点
for (i = 1; i < n; ++i) {
//将v0顶点与之有边的权值存入数组
lowcost[i] = graph[0][i];
adjvex[i] = 0;
}
for (i = 1; i < n; ++i) {
min = INFINITY; //初始化最小权值为无穷
j = 1, k = 0;
//循环全部顶点,找到最小权值
while (j < n) {
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
k = j;
}
++j;
}
//输出最小权值边
cout << map[adjvex[k]] << "->" << map[k] << "=" << min << endl;
sum += min;
lowcost[k] = 0; //将下标为k的顶点加入MST
//更新lowcost为加入的顶点的所有边
for (j = 1; j < n; ++j) {
if (lowcost[j] != 0 && graph[k][j] < lowcost[j]) {
lowcost[j] = graph[k][j];
adjvex[j] = k;
}
}
}
return sum;
}
完整代码:
#include <iostream>
#include <fstream>
using namespace std;
#define MAXVEX 100
#define INFINITY 65535
int graph[MAXVEX][MAXVEX];
char map[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g',' h', 'i' };
int Prim(int graph[][MAXVEX], int n) {
int i, j, k, min, sum = 0;
int adjvex[MAXVEX];
int lowcost[MAXVEX];
lowcost[0] = 0;
adjvex[0] = 0;
for (i = 1; i < n; ++i) {
lowcost[i] = graph[0][i];
adjvex[i] = 0;
}
for (i = 1; i < n; ++i) {
min = INFINITY;
j = 1, k = 0;
while (j < n) {
if (lowcost[j] != 0 && lowcost[j] < min) {
min = lowcost[j];
k = j;
}
++j;
}
cout << map[adjvex[k]] << "->" << map[k] << "=" << min << endl;
sum += min;
lowcost[k] = 0;
for (j = 1; j < n; ++j) {
if (lowcost[j] != 0 && graph[k][j] < lowcost[j]) {
lowcost[j] = graph[k][j];
adjvex[j] = k;
}
}
}
return sum;
}
int main(int argc, char**argv) {
int i, j, k, cost;
int m, n;
ifstream in("input.txt");
in >> n >> m; //输入顶点个数及边的数量
//初始化邻接矩阵
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
graph[i][j] = INFINITY;
}
}
//构建图
for (k = 0; k < m; ++k) {
in >> i >> j >> cost;
graph[i][j] = cost;
graph[j][i] = cost;
}
cost = Prim(graph, n); //调用Prim算法
cout << "Minimum weight sum: " << cost << endl;
return 0;
}
9 15
0 1 10
0 5 11
1 2 18
1 6 12
1 7 12
2 3 22
2 7 8
3 4 20
3 6 24
3 7 21
3 8 16
4 5 26
4 8 7
5 6 17
6 8 19
a->b=10
a->f=11
b->g=12
b-h=12
h->c=8
g->i=19
i->e=7
i->d=16
Minimun weight num: 95
由算法代码中的循环嵌套可以得知此算法的时间复杂度为