ACM Note No.11: MST


ACM Note No.11: MST

最小生成树(Minimum Spanning Tree,MST),是一个有权图删除若干边能得到的边权和最小的树

常见的求最小生成树的算法有 Prim 算法Kruskal 算法

Kruskal 算法

从小到大加入边,直到所有的点连通

由于需要判断所有点是否连通,自然就想到可以用并查集实现

Luogu P3366

#include <bits/stdc++.h>
using namespace std;
struct node{
    // x 到 y 有一条权值为 w 的边
    int x, y, w;
};
// 并查集封装
struct DSU {
    vector<int> fa;
    int n;
    DSU(int size) {
        n = size;
        fa = vector<int>(n);
        for(int i = 0; i < n; i++){
            fa[i] = i;
        }
    };
    int find(int x) {
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    void merge(int x, int y) {
        fa[find(x)] = fa[find(y)];
    }
    bool query(int x, int y){
        return find(x) == find(y);
    }
};
int main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    // 存储所有边
    vector<node> edges;
    for(int i = 0; i < m; i++){
        int x, y, z;
        cin >> x >> y >> z;
        x--, y--;
        edges.push_back({x, y, z});
    }
    // 对所有边从大到小排序便于后续进行贪心
    sort(edges.begin(), edges.end(), [](node a, node b) -> bool {
        return a.w < b.w;
    });
    DSU dsu(n);
    vector<node> res;
    for(auto nd : edges){
        // 如果加入边不改变图的联通性就跳过
       if(dsu.query(nd.x, nd.y)){
            continue;
        }
        // 加入边并改变图的连通性
        dsu.merge(nd.x, nd.y);
        res.push_back(nd);
        // 边数 == 节点数 - 1 时说明已经构成了一棵树
        if(res.size() == n - 1){
            break;
        }
    }
    int sum = 0;
    for(node nd : res){
        sum += nd.w;
    }
    cout << (res.size() == n - 1 ? to_string(sum) : "orz");
    return 0;
}

Prim 算法

同样是一种贪心算法,过程类似 Dijkstra

因为 Prim 算法效率一般不优于 Kruskal 算法所以一般来说使用 Kruskal 算法寻找最小生成树

声明:Blog|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - ACM Note No.11: MST