#include <iostream>
#include <climits> /* for INT_MAX */
using namespace std;
/** 顶点数最大值. */
const int MAX_NV = 100;
/** 边的权值类型,可以为int, float, double. */
typedef int graph_weight_t;
const graph_weight_t GRAPH_INF = INT_MAX;
/**
* @struct 图,用邻接矩阵(Adjacency Matrix).
*/
struct graph_t {
int nv; // 顶点数
int ne; // 边数
// 邻接矩阵,存放边的信息,如权重等
graph_weight_t matrix[MAX_NV][MAX_NV];
};
graph_t g;
struct closedge_t {
int adjvex; /* 弧尾,属于U,注:弧尾是弧的起点,弧头是弧的终点,因为终点带有箭头,所以叫弧头 */
/* 边adjvex-> 本下标的权值,-GRAPH_INF 表示已经加入U */
graph_weight_t lowcost;
};
/*
* @brief 在V-E 集合中寻找最小的边
* @param[in] closedge MST 中的边,起点为adjvex,终点为本下标
* @param[in] n closedge 数组的长度
* @return 找到了则返回弧头的下标,V-U 为空集则返回-1,表示终止
*/
static int min_element(const closedge_t closedge[], int n) {
int min_value = GRAPH_INF;
int min_pos = -1;
for (int i = 0; i < n; i++)
if (closedge[i].lowcost > -GRAPH_INF) {
if (min_value > closedge[i].lowcost) {
min_value = closedge[i].lowcost;
min_pos = i;
}
}
return min_pos;
}
/**
* @brief Prim 算法,求图的最小生成树.
* @param[in] g 图对象的指针
* @return MST 的边的权值之和
*/
graph_weight_t prim(const graph_t &g) {
graph_weight_t sum = 0; /* 权值之和*/
int u = 0; /* 从0 号顶点出发*/
const int n = g.nv;
/* closedge[n],记录从顶点集U 到V-U 的边*/
closedge_t* const closedge = new closedge_t[n];
/* 辅助数组初始化*/
for (int i = 0; i < n; i++) if (i != u) {
closedge[i].adjvex = u;
closedge[i].lowcost = g.matrix[u][i];
}
closedge[u].lowcost = -GRAPH_INF; /* 初始, U={u} */
for (int i = 0; i < n; i++) if (i != u) { /* 其余的n-1 个顶点*/
/* 求出TE 的下一个顶点k */
const int k = min_element(closedge, n);
/* 输出此边closedge[k].adjvex --> k */
cout << (char)('A' + closedge[k].adjvex) << " - " << (char)('A' + k)
<< " : "<< g.matrix[closedge[k].adjvex][k] << endl;
sum += g.matrix[closedge[k].adjvex][k];
// sum += closedge[k].lowcost; // 等价
closedge[k].lowcost = -GRAPH_INF; /* 顶点k 并入U,表示此边加入TE */
/* 更新k 的邻接点的值,不相邻为无穷大*/
for (int j = 0; j < n; j++) {
const graph_weight_t w = g.matrix[k][j];
if (w < closedge[j].lowcost) {
closedge[j].adjvex = k;
closedge[j].lowcost = w;
}
}
}
delete[] closedge;
return sum;
}
/** 读取输入,构建图. */
void read_graph() {
int m, n;
/* 读取节点和边的数目*/
cin >> m >> n;
g.nv = m;
g.ne = n;
/* 初始化图,所有节点间距离为无穷大*/
for (int i = 0; i < m; i++) {
for (int j = 0; j < m; j++) {
g.matrix[i][j] = GRAPH_INF;
}
}
/* 读取边信息*/
for (int k = 0; k < n; k++) {
char chx, chy;
int w;
cin >> chx >> chy >> w;
const int i = chx - 'A';
const int j = chy - 'A';
g.matrix[i][j] = w;
g.matrix[j][i] = w;
}
}
int main() {
read_graph();
cout << "Total : " << prim(g) << endl;
return 0;
}
/* test
输入数据:
7 11
A B 7
A D 5
B C 8
B D 9
B E 7
C E 5
D E 15
D F 6
E F 8
E G 9
F G 11
输出:
A - D : 5
D - F : 6
A - B : 7
B - E : 7
E - C : 5
E - G : 9
Total:39
*/
Prim算法求最小生成树
最新推荐文章于 2022-11-16 21:29:22 发布