洛谷P3366 【模板】最小生成树 题解

题目链接:https://www.luogu.org/problem/P3366
最小生成树模板题。

Kruskal算法

算法思想:给边按边权从小到大排序,然后遍历每一条边,如果边上的两个点不在同一个集合,则选择这条边,并将两个点所在集合合并。直到选择了 \(n-1\) 条边。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200200;
int n, m, f[5050], cnt, u[maxn], v[maxn], idx[maxn];
long long ans, w[maxn];
void init() {
    for (int i = 1; i <= n; i ++) f[i] = i;
}
int func_find(int x) {
    return x == f[x] ? x : f[x] = func_find(f[x]);
}
void func_union(int x, int y) {
    int a = func_find(x), b = func_find(y);
    f[a] = f[b] = f[x] = f[y] = min(a, b);
}
bool cmp(int i, int j) { return w[i] < w[j]; }
int main() {
    cin >> n >> m;
    init();
    for (int i = 0; i < m; i ++) {
        cin >> u[i] >> v[i] >> w[i];
        idx[i] = i;
    }
    sort(idx, idx+m, cmp);
    for (int k = 0; k < m; k ++) {
        int i = idx[k];
        if (func_find(u[i]) != func_find(v[i])) {
            func_union(u[i], v[i]);
            cnt ++;
            ans += w[i];
            if (cnt == n-1) break;
        }
    }
    if (cnt < n-1) puts("orz");
    cout << ans << endl;
    return 0;
}

Prim算法

算法思想:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5050;
#define INF (1<<29)
int n, m, dis[maxn];
bool vis[maxn];
struct Node {
    int v, w;
    Node () {}
    Node (int _v, int _w) { v = _v; w = _w; }
};
vector<Node> g[maxn];
void prim() {
    int ans = 0;
    dis[1] = 0;
    for (int i = 2; i <= n; i ++) dis[i] = INF;
    for (int i = 0; i < n; i ++) {
        int id = 0;
        for (int j = 1; j <= n; j ++) if (!vis[j] && (!id || dis[j] < dis[id])) id = j;
        if (!id || dis[id] == INF) {
            puts("orz");
            return;
        }
        ans += dis[id];
        vis[id] = true;
        int sz = g[id].size();
        for (int j = 0; j < sz; j ++) {
            int v = g[id][j].v, w = g[id][j].w;
            if (vis[v]) continue;
            if (dis[v] > w) dis[v] = w;
        }
    }
    cout << ans << endl;
}
int main() {
    cin >> n >> m;
    while (m --) {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back(Node(v, w));
        g[v].push_back(Node(u, w));
    }
    prim();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/codedecision/p/11783171.html