最小生成树
Posted nioh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最小生成树相关的知识,希望对你有一定的参考价值。
给定边权为正的连通图G,找出连接所有顶点的边的最小权值(集)。
Kruskal:
步骤:
1. 按边权从小到大的顺序遍历边。
2. 如果边对应的两个点不在同一连通分量中,则将其相连。否则忽略。
贪心 + 并查集,时间复杂度$O(ElogE+E*A(V)+V)(A is Ackermann)$。
Prim:
步骤:
1. S = {x}(x为任意点)。
2. 重复以下操作直到S中有V个点。
设E是只有一个端点在S的边中的最小边。
将另一个端点加入S。
贪心 + 优先级队列,时间复杂度$O((E+V)log(V))$。
例题:洛谷P3366
https://www.luogu.com.cn/problem/P3366
1. Kruskal
#include<bits/stdc++.h> using namespace std; const int N = 200010; int n, m, w[N], u[N], v[N], f[5010], o[N]; int cmp(int a, int b) {return w[a] < w[b];} int find(int k) {return f[k] == k ? k : f[k] = find(f[k]);} int Kruskal() { int ans = 0; for(int i = 0; i < n; i++) f[i] = i; for(int i = 0; i < m; i++) o[i] = i; sort(o, o + m, cmp); for(auto e : o) { if(find(u[e]) != find(v[e])) f[f[u[e]]] = f[v[e]], ans += w[e]; } return ans; } int main() { cin >> n >> m; for(int i = 0; i < m; i++) cin >> u[i] >> v[i] >> w[i]; cout << Kruskal(); }
2. Prim
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> pii; vector<pii> g[5010]; int n, m, x, y, z; int Prim() { priority_queue<pii, vector<pii>, greater<pii> > pq; int ans = 0, d[5010] = {0}; pq.push(make_pair(0, 1)); while(!pq.empty()) { pii c = pq.top(); pq.pop(); if(!d[c.second]) d[c.second] = 1, ans += c.first; else continue; for(int i = 0; i < g[c.second].size(); i++) { pii a = g[c.second][i]; if(!d[a.second]) pq.push(a); } } return ans; } int main() { cin >> n >> m; for(int i = 0; i < m; i++) { cin >> x >> y >> z; g[x].push_back(make_pair(z, y)); g[y].push_back(make_pair(z, x)); } cout << Prim(); }
以上是关于最小生成树的主要内容,如果未能解决你的问题,请参考以下文章