Prim算法求最小生成树,思想类似Dijkstra最短路径算法,可以用于稠密图。
Kruskal算法是每次加边,Prim是每次加一个点,并且始终是树.
【过程】
1 从任意顶点开始构造生成树。用标记记录哪些顶点已经加入生成树.
2 用dis数组存储生成树到每个顶点的距离
3 在dis中找最小值,就是离生成树最近的顶点。再用这个点更新dis(松弛)
4 重复3,直到包含n个点.
(一)一般的算法
#include <iostream>
using namespace std;
const int MAX = 1e7;
int n, m;
int G[5001][5001]; //邻接矩阵存图
bool flag[5001]; //标记是否在生成树中
int dis[5001]; //生成树到顶点到距离
int cnt; //生成树中的顶点个数
int sum; //最小生成树费用
void Prim() {
/*从第一个顶点开始*/
for(int i=1; i<=n; i++) dis[i] = G[1][i];
flag[1] = true;
cnt ++;
while(cnt < n) {
int min = MAX;
int k; //记录最小距离的顶点编号
for(int i=1; i<=n; i++)
if(!flag[i] && dis[i] < min) {
min = dis[i];
k = i;
}
flag[k] = true; //把最小距离的那个顶点加入生成树
cnt ++;
sum += dis[k];
for(int i=1; i<=n; i++)
if(!flag[i] && dis[i] > G[k][i])
dis[i] = G[k][i]; //更新
}
cout << sum << endl;
}
int main() {
int u, v, w;
cin >> n >> m;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
G[i][j] = ((i==j)?0:MAX);
for(int i=1; i<=m; i++) {
cin >> u >> v >> w;
G[u][v] = G[v][u] = min(G[u][v], w);
}
Prim();
return 0;
}
(二)堆优化