最小生成树

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();
}

 

以上是关于最小生成树的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树matlab代码Kruskal算法,用于二维网络生成

c语言最小生成树

最小生成树及Prim算法及Kruskal算法的代码实现

数据结构 图连通与最小生成树

次最小生成树 模版

图的最小生成树算法(图解+代码)| 学不会来看我系列