• 算法(图论)——最小生成树及其题目应用(prim和Kruskal算法实现)


    题目

    n个村庄间架设通信线路,每个村庄间的距离不同,如何架设最节省开销?

    Kruskal算法

    特点

    • 适用于稀疏图,时间复杂度 是nlogn的。

    核心思想

    • 从小到大选取不会产生环的边。

    代码实现

    代码中需要采用并查集的方法检测是否有环。

        static class Edge {
            int a, b, val;
            public Edge(int a, int b, int val) {
                this.a = a;
                this.b = b;
                this.val = val;
            }
        }
    
        int[] father;
        // 并查集——寻找当前集合的代表元素
        int find(int x) {
            if (father[x] != x) father[x] = find(father[x]);
    
            return father[x];
        }
        int Kruskal(Edge[] edge) {
            int res = 0;
            int n = edge.length;
            father = new int[n];
            // 初始化并查集代表元素
            for (int i = 1; i <= n; i ++ ) father[i] = i;
            // 升序排序
            Arrays.sort(edge, (a, b) -> a.val - b.val);
            for (Edge value : edge) {
                int a = value.a, b = value.b;
                // 如果不会产生环,则添加边
                if (find(a) != find(b)) {
                    res += value.val;
                    // 合并两个点到一个块中
                    father[find(a)] = find(b);
                }
            }
            return res;
        }
    

    prim算法

    特点

    • 适用于稠密图,时间复杂度 是n方的。

    核心思想

    • 每次挑选与当前集合连接的最短边。

    代码实现

    public int Prim() {
        int res = 0;
        for (int i = 1; i <= n; i ++ ) {
            dist[i] = INF;
            st[i] = false;
        }
        dist[1] = 0;
        for (int i = 1; i <= n; i ++ ) {
            int id = -1, min_dist = INF;
            // 寻找最短边
            for (int j = 1; j <= n; j ++ )
                if (!st[j] && dist[j] < min_dist) {
                    id = j;
                    min_dist = dist[j];
                }
            st[id] = true;
            res += dist[id];
            // 用新加入的点更新其余点到生成树的最短边
            for (int j = 1; j <= n; j ++ )
                if (!st[j])
                    dist[j] = min(dist[j], g[id][j]);
        }
        return res;
    }
    

    总结

    还是Kruskal算法更容易实现一些,只要遍历每条边就好了。

  • 相关阅读:
    二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment
    思维题 HDOJ 5288 OO’s Sequence
    树形DP Codeforces Round #135 (Div. 2) D. Choosing Capital for Treeland
    最大流增广路(KM算法) HDOJ 1853 Cyclic Tour
    最大流增广路(KM算法) HDOJ 1533 Going Home
    最大流增广路(KM算法) HDOJ 2255 奔小康赚大钱
    Complete the Word CodeForces
    Gadgets for dollars and pounds CodeForces
    Vasya and Basketball CodeForces
    Carries SCU
  • 原文地址:https://www.cnblogs.com/lippon/p/14117645.html
Copyright © 2020-2023  润新知