zoukankan      html  css  js  c++  java
  • 最小生成树(Kruskal & Prim)

    例题

    kruskal

    • Kruskal算法通过并差集维护,从到小枚举每条边,如果两端点不在一个集合,将两端点所在集合合并,并将边权累加到答案中

    • 时间复杂度为(O(m log m))

    • 评测记录

      • code
        #include <cstdio>
        #include <algorithm>
        using namespace std;
        const int N = 5005, M = 2e5+5;
        struct side {
            int x, y, d;
        }e[M];
        bool operator < (side a, side b) {
            return a.d < b.d;
        }
        int n, m, f[N], ans, cnt;
        int found(int x) {
            return x == f[x] ? x : (f[x] = found(f[x]));
        }
        void kruskal() {
            for (int i = 1; i <= m; i++) {
                int x = found(e[i].x), y = found(e[i].y);
                if (x == y) continue;
                f[x] = y;
                ans += e[i].d;
                if (++cnt == n-1) return;//最小生成树上最多n-1条边
            }
        }
        int main() {
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= m; i++)
                scanf("%d%d%d", &e[i].x, &e[i].y, &e[i].d);
            sort(e + 1, e + m + 1);//排序
            for (int i = 1; i <= n; i++) f[i] = i;//并查集初始化
            kruskal();
            if (cnt == n-1) printf("%d
        ", ans);
            else puts("orn");//奇奇怪怪的输出,其实他没有这个测试点
            return 0;
        }
        

    prim

    • Prim算法思想类似于Dijkatra。
      维护一个数组 d[x] 节点 x 与已确定是最小生成树集合中的节点之间权值最小的边的权值
      每次从未标记的节点中选出 d 值最小的点,将其标记,在更新其他点的 d 值

    • 时间复杂度为(O(n^2)),使用堆优化可以到(O(mlogn))(这里写的是堆优化后的板子) 但是这样不如Kruskal方便,
      因此,Prim主要用于稠密图,尤其是完全图的求解

    • 评测记录

      • code
        #include <queue>
        #include <cstdio>
        #include <cstring>
        using namespace std;
        const int N = 5005, M = 2e5+5;
        struct side{
            int t, d, next;
        }e[M<<1];
        int head[N], tot;
        void add(int x, int y, int z) {
            e[++tot].next = head[x];
            head[x] = tot;
            e[tot].t = y;
            e[tot].d = z;
        }
        priority_queue< pair<int, int> > q;
        int n, m, d[N], ans, cnt;
        bool v[N];
        void prim() {
            memset(d, 0x3f, sizeof(d));
            q.push(make_pair(d[1] = 0, 1));
            while (!q.empty() && cnt < n) {
                int x, w;
                x = q.top().second;
                w = -q.top().first;
                q.pop();
                if (v[x]) continue;
                v[x] = 1;
                ans += w;
                cnt++;
                for (int i = head[x]; i; i = e[i].next) {
                    int y = e[i].t;
                    if (d[y] > e[i].d) {
                        d[y] = e[i].d;
                        q.push(make_pair(-d[y], y));
                    }
                }
            }
        }
        int main() {
            scanf("%d%d", &n, &m);
            while (m--) {
                int x, y, z;
                scanf("%d%d%d", &x, &y, &z);
                add(x, y, z); add(y, x, z);
            }
            prim();
            if (cnt == n) printf("%d
        ", ans);
            else puts("orn");
            return 0;
        }
        
  • 相关阅读:
    克如斯卡尔 P1546
    真正的spfa
    第四课 最小生成树 要点
    关于vscode中nullptr未定义
    cmake学习笔记
    python学习笔记
    (BFS 图的遍历) 2906. kotori和迷宫
    (图论基础题) leetcode 997. Find the Town Judge
    (BFS DFS 并查集) leetcode 547. Friend Circles
    (BFS DFS 图的遍历) leetcode 841. Keys and Rooms
  • 原文地址:https://www.cnblogs.com/Z8875/p/13229244.html
Copyright © 2011-2022 走看看