最小生成树
最小生成包含两种算法
- Prim O(n ^ 2)
- Kruskal O(mlogm)
Prim
主要分为两种朴素版Prim,堆优化版Prim
朴素版Prim时间复杂度是O(n ^ 2)
堆优化版代码过于复杂建议使用Kruskal
流程
初始化d数组为正无穷
d[1] = 0
for循环迭代n次,找到集合外距离集合最近的点t,然后用t来更新每一个点到起点的距离
最终将t放入到st集合中
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] == 0x3f3f3f3f) return 0x3f3f3f3f; if(i) res += d[t];
for(int j = 1;j <= n;j++) { d[j] = min(d[j],g[t][j]); }
st[t] = 1; }
return res; }
|
heap + Prim算法代码非常多,不推荐写
Kruskal
时间复杂度为O(mlogm)
Step
- 将所有边按照权重进行排序
- 枚举每条边a,b,权重为c,如果a,b不连通,将这条边加入到集合中
如何将两个点连通可以参考一下并查集,p[a] = b
Kruskal代码
int kruskal() { sort(edges,edges + m,cmp); for(int i = 1;i <= n;i++) p[i] = i;
int res = 0,cnt = 0; for(int i = 0;i < m;i++) { int a = edges[i].a,b = edges[i].b,c = edges[i].c; a = find(a),b = find(b); if(a != b) { p[a] = b; res += c; cnt++; } } if(cnt < n - 1) return INF; return res; }
|