prim算法求最小生成树
#include <iostream> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int N = 501, INF = 0x3f3f3f3f; int d[N], g[N][N]; int n, m; bool st[N]; int prim() { memset(d, 0x3f, sizeof d); int res = 0;//所有长度之和 for(int i = 0; i < n;i++) { int t = -1; for(int j = 1; j <= n;j++) if(!st[j] && (t == -1 || d[t] > d[j])) t = j; if(i && d[t] == INF) return INF; if(i) res += d[t]; st[t] = true; for(int j = 1;j <= n;j++) d[j] = min(d[j], g[t][j]);//注意这里与Dijkstra区别d[t] + d[t][j] } return res; } int main() { ios::sync_with_stdio(false); cin>>n>>m; memset(g, 0x3f, sizeof g); while(m--) { int a,b,c; cin>>a>>b>>c; g[a][b] = g[b][a] = min(g[a][b], c); } int t = prim(); if(t == INF) puts("impossible"); else cout<<t<<endl; }
prime算法和Dijkstra算法求最小距离非常相似。
一开始d[i]全都被赋值为+oo
要找n个点,那么就要循环n次
for i 0 - n
找到集合外距离最近的点,用新的距离最近的点t来更新其他点到集合的最短距离(Dijkstra这里是更新到起点的距离),st[t] = true;加入到集合当中来。
必须要先累加再更新,如果有负权自环的话,就会再次更新自己 从而加入进来,先累加再更新下一次判断的话因为st[j] = true就不会再更新了。
模拟一遍:i = 0, t = 1, d[1] = oo, 但是不会加入最小生成树的res里面来,因为只有i>0 时,res += d[t]。d[2] = 1, d[3] = 2, d[4] = 3。
接着会用连接的最小距离2来更新其他点。注意是到集合的距离,所以也只是min(d[t], g[t][j]), 而Dijkstra是min(d[t], d[t] + g[t][j]);