普里姆算法(Prim)

普里姆算法的应用场景为修路问题,就是用最小的路径连接所有节点

转换一下就是最小生成树(MST)的问题:给定一个带权的无向连接图,如何选取一颗生成树,使树上的所有的边上权的总和为最小,就是最小生成树

普里姆算法求最小生成树:在包含n个顶点的连接图中,找出只有(n-1)条边并包含所有n个顶点的连通子图,即极小连通子图

过程:

设G={V,E}是连通网,T={U,D}是最小生成树,V,U是顶点的集合,E,D是边的集合

从顶点u开始构造最小生成树,则从V中取出u放到U中,并标记顶点v的visited[u]=1

若集合U中顶点u和V中顶点之间存在边,则寻找最小边,并不构成回路,将此节点加入U中并将边加到D中

重复第2步骤,知道U,V相等(就是所有顶点被访问过),此时D中则有n-1条边

import java.util.Arrays;

public class PrimAlgorithm {

    public static void main(String[] args) {
        char[] data = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        int verxs = data.length;
        int[][] weight = new int[][]{
                {10000, 5, 7, 10000, 10000, 10000, 2},
                {5, 10000, 10000, 9, 10000, 10000, 3},
                {7, 10000, 10000, 10000, 8, 10000, 10000},
                {10000, 9, 10000, 10000, 10000, 4, 10000},
                {10000, 10000, 8, 10000, 10000, 5, 4},
                {10000, 10000, 10000, 4, 5, 10000, 6},
                {2, 3, 10000, 10000, 4, 6, 10000},
        };
        MGraph graph = new MGraph(verxs);
        MinTree minTree = new MinTree();
        minTree.createGraph(graph, verxs, data, weight);
        minTree.showGraph(graph);
        minTree.prim(graph,0);

    }
}

class MinTree {
    /**
     * @param graph  图对象
     * @param verxs  图对应的顶点个数
     * @param date   图的各个顶点的值
     * @param weight 图的邻接矩阵
     */
    public void createGraph(MGraph graph, int verxs, char[] date, int[][] weight) {
        int i, j;
        for (i = 0; i < verxs; i++) {
            graph.data[i] = date[i];
            for (j = 0; j < verxs; j++) {
                graph.weight[i][j] = weight[i][j];
            }
        }
    }

    public void showGraph(MGraph graph) {
        for (int[] link : graph.weight) {
            System.out.println(Arrays.toString(link));
        }
    }

    /**
     * prim算法生成最小树
     *
     * @param graph 图
     * @param v     从第几个节点生成
     */
    public void prim(MGraph graph, int v) {
        //标记节点是否访问过
        int[] visited = new int[graph.verxs];
        visited[v] = 1;
        //记录两个节点的下标
        int h1 = -1;
        int h2 = -1;
        int minWeight = 10000;
        //循环节点数-1次
        for (int k = 1; k < graph.verxs; k++) {
            for (int i = 0; i < graph.verxs; i++) {//i被访问的节点
                for (int j = 0; j < graph.verxs; j++) {//j没有被访问的节点
                    if (visited[i] == 1 && visited[j] == 0
                            && graph.weight[i][j] < minWeight) {
                        //替换 minWeight
                        minWeight = graph.weight[i][j];
                        h1 = i;
                        h2 = j;
                    }
                }
            }
            System.out.println("边<" + graph.data[h1] + "," + graph.data[h2] + "> 权值=" + minWeight);
            visited[h2] = 1;
            minWeight = 10000;
        }
    }
}

class MGraph {
    int verxs;//节点数
    char[] data;//节点数据
    int[][] weight;//边 (邻接矩阵)

    public MGraph(int verxs) {
        this.verxs = verxs;
        data = new char[verxs];
        weight = new int[verxs][verxs];
    }
}

猜你喜欢

转载自www.cnblogs.com/bingbug/p/12371080.html