zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    
  • 相关阅读:
    11个Linux基础面试问题
    OSI模型
    戴文的Linux内核专题:10配置内核(6)
    面向对象实验四(输入输出流)
    计算机程序的思维逻辑 (2)
    计算机程序的思维逻辑 (1)
    java基础3.0:Java常用API
    java基础2.0:Object、Class、克隆、异常编程
    java基础1.0::Java面向对象、面向对象封装、抽象类、接口、static、final
    Ajax工作原理(转)
  • 原文地址:https://www.cnblogs.com/codedecision/p/11783171.html
Copyright © 2011-2022 走看看