Data Structure and Algorithm-Analysis of Prim Algorithm and Solving the Minimum Spanning Tree Problem of Road Construction

Introduction

Prim algorithm

​Prim's algorithm (Prim's algorithm), an algorithm in graph theory, can search for a minimum spanning tree in a weighted connected graph. It means that the tree formed by the edge subset searched by this algorithm not only includes all the vertices in the connected graph, but also the sum of the weights of all the edges is the minimum. The algorithm was discovered in 1930 by the Czech mathematician Vojtech Jarnik; and independently discovered in 1957 by the American computer scientist Robert Prim); in 1959, Ezger Dijkstra discovered the algorithm again algorithm. Therefore, in some occasions, Prim's algorithm is also called DJP algorithm, Yarnik algorithm or Prim-Yarnik algorithm (quoted from Baidu Encyclopedia).

minimum spanning tree

​ The Prim algorithm is mainly used in finding the minimum spanning tree problem ( 克鲁斯卡尔算法也适用于这种问题,**prim**算法适合稠密图,其时间复杂度为O(n^2),其时间复杂度与边得数目无关,而**kruskal**算法的时间复杂度为O(nlogn)跟边的数目有关,适合稀疏图), given an undirected graph G = ( V, E ), n=| V |, m=| E |. An undirected connected subgraph consisting of all n vertices in V and n-1 edges in E is called a spanning tree of G. The spanning tree with the minimum sum of edge weights is called the minimum spanning tree (Minimum Spanning Tree, MST) of the undirected graph G. Any minimum spanning tree must contain the edge with the smallest weight in the undirected graph.

insert image description here

Application Scenario

Problem Description

insert image description here

​ There are 7 villages (A, B, C, D, E, F, G), and now it is necessary to build roads to connect the 7 villages. The distance between each village is represented by a sideline (right), for example, the distance between A and B is 5 kilometers, Question: How to build roads to ensure that all villages can be connected, and the total road mileage is the shortest?
​ Idea: Just connect 10 sides, but the total mileage is not the smallest. The correct way of thinking is to choose as much as possible There are few routes, and each route is the smallest to ensure that the total mileage is the least.

Idea analysis

1.从A顶点开始处理 => <A,G> 2
A-C [7] A-G[2] A-B[5]
2.<A,G> 开始 , 将A 和 G 顶点和他们相邻的还没有访问的顶点进行处理 =><A,G,B>
A-C[7] A-B[5] G-B[3] G-E[4] G-F[6]
3.<A,G,B> 开始,将A,G,B 顶点 和他们相邻的还没有访问的顶点进行处理=><A,G,B,E>
A-C[7] G-E[4] G-F[6] B-D[9]
…
4.{A,G,B,E}->F//第4次大循环 , 对应边<E,F> 权值:5
5.{A,G,B,E,F}->D//第5次大循环 , 对应边<F,D> 权值:4
6.{A,G,B,E,F,D}->C//第6次大循环 , 对应边<A,C> 权值:7 => <A,G,B,E,F,D,C>

Code

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 num = data.length;
        // 邻接矩阵的关系使用二维数组表示,使用10000这个比较大的数值表示两点不连通
        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(num);
        // 创建一个minTree对象
        MinTree minTree = new MinTree();
        minTree.createGraph(graph, num, data, weight);
        // 打印图
        minTree.showGraph(graph);
        minTree.prim(graph, 0);
    }

    static class MGraph {
    
    
        // 表示图的节点数量
        int num;
        // 存放节点数据
        char[] data;
        // 存放边,即邻接矩阵
        int[][] weight;

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

    // 最小生成树->村庄的图
    static class MinTree {
    
    

        /**
         * 创建图的邻接矩阵
         *
         * @param graph  图
         * @param num    图对应的节点数量
         * @param data   图的各个节点的值
         * @param weight 图的邻接矩阵
         */
        public void createGraph(MGraph graph, int num, char[] data, int[][] weight) {
    
    
            // int i, j;
            for (int i = 0; i < num; i++) {
    
    
                graph.data[i] = data[i];
                for (int j = 0; j < num; 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     表示从图的第几个节点开始生成'A'->0 'B'->1 ...
         */
        public void prim(MGraph graph, int v) {
    
    
            // 标记节点是否被访问过
            int[] visited = new int[graph.num];
            // 把当前节点标记为已访问
            visited[v] = 1;
            // 使用h1和h2记录两个节点的下标
            int h1 = -1;
            int h2 = -2;
            // 记录最小距离,将minWeight初始成一个大数,后面遍历过程中会被替换
            int minWeight = 10000;
            // 因为有graph.num个节点,普利姆算法结束后,有graph.num-1条边
            for (int k = 1; k < graph.num; k++) {
    
    
                // 确定每一次生成的子图,和哪个节点的距离最近
                // i节点表示被访问过的节点
                for (int i = 0; i < graph.num; i++) {
    
    
                    // j节点表示没被访问过的节点
                    for (int j = 0; j < graph.num; j++) {
    
    
                        if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < 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
                minWeight = 10000;
            }
        }
    }

}

Output result:

[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]<AG> 权值:2<GB> 权值:3<GE> 权值:4<EF> 权值:5<FD> 权值:4<AC> 权值:7
 10000, 10000, 5, 4]
[10000, 10000, 10000, 4, 5, 10000, 6]
[2, 3, 10000, 10000, 4, 6, 10000]<AG> 权值:2<GB> 权值:3<GE> 权值:4<EF> 权值:5<FD> 权值:4<AC> 权值:7

Guess you like

Origin blog.csdn.net/qq_38951230/article/details/127287829