P3366 【模板】最小生成树
//prim算法求最小生成树
#include <iostream> #include <cstring> using namespace std; const int N = 5010, INF = 0x3f3f3f3f; int n, m, d[N], g[N][N]; bool st[N]; int prime() { 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; st[t] = true; if(i){ if(d[t] == INF) return INF; res += d[t]; } for(int j = 1; j <= n; j ++) if(d[j] > g[t][j]) d[j] = g[t][j]; } return res; } int main() { 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 = prime(); if(t == INF) cout << "orz" << endl; else cout << t << endl; }
Kruskal算法求最小生成树:
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; const int N = 5010, M = 2e5 + 10; int n, m, p[N]; struct Node{ int a, b, w; bool operator < (const Node &t)const { return w < t.w; } }node[M]; int find(int x) { if(x != p[x]) p[x] = find(p[x]); return p[x]; } int main() { cin >> n >> m; for(int i = 0; i < m; i ++) p[i] = i; for(int i = 0; i < m; i ++) { int a, b, w; cin >> a >> b >> w; node[i] = {a, b, w}; } sort(node, node + m); int res = 0, cnt = 0; for(int i = 0; i < m; i ++) { int a = node[i].a, b = node[i].b, w = node[i].w; int x = find(a), y = find(b); if(x != y) { p[x] = y; cnt ++; res += w; } } if(cnt < n - 1) puts("orz"); else cout << res << endl; }
可以看到,prime求最小生成树和dijkstra求最短路神奇的相似,不同之处在于生成树要把每条路径加进来,所以开始 i = 0时,d[t]为INF,不能加进来,每次贪心选择最小的边,然后向外扩展得到能扩展边的最小值等于d[j] = g[t][j],把它们都加到最小生成树里面res来。以点来进行扩展,所以复杂度是O(n^2)。
而Kruskal算法则是枚举每条边,用贪心的方法从小到大把每条不在同一个连通块内的边(用并查集来判断)加进来,如果最后加进来的边的数目小于 n - 1,即没有把所有的点加进来,图不连通。