【Java数据结构与算法】普利姆算法
普利姆算法(Prim)和MST介绍
应用场景
修路问题
- 乡村有7个村庄(A,B,C,D,E,F,G),现在需要修路把7个村庄连通。
- 各个村庄的举例用边线表示(权),比如A-B距离5公里。
- 问:如何修路保证各个村庄都能连通,并且修建公路总里程最短?
- 如果将所有边都连通,虽然每个村庄都连通了,但总里程数不是最小。
- 所以应该在保证连通的情况下,尽可能选择少的路线,且每条路线最小,才能保证总的里程数最少。
最小生成树
修路问题本质就是最小生成树问题,先介绍一下最小生成树(Minimum Cost Spanning Tree),简称MST。
- 给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树。
- N个顶点,一定有N-1条边。
- 包含全部顶点。
- N-1条边都在图中。
- 求最小生成树的算法主要是普利姆算法和克鲁斯卡尔算法。
Prim算法解决修路问题思路分析
基本介绍
- 普利姆(Prim)算法求最小生成树,也就是在包含n个顶点的连通图中,找出只有(n-1)条边包含所有n个顶点的连通子图,也就是所谓的极小连通子图。
- 普利姆算法如下:
- 设G=(V,E)是连通网,T=(U,D)是最小生成树,V,U是顶点集合,E,D是边的集合。
- 若从顶点u开始构造最小生成树,则从集合V中取出顶点u放入集合U中,标记顶点v的visited[u]=1。
- 若集合U中顶点ui与集合V-U中的顶点vj之间存在边,则寻找这些边中权值最小的边,但不能够成回路,将顶点vj加入集合U中,将边(ui,vj)加入集合D中,标记visited[vi]=1。
- 重复步骤2,直到U与V相等,即所有顶点都被标记为访问过,此时D中有n-1条边。
- 提示:算法步骤看着很难理解,通过代码比较好理解。
思路分析
-
从{A}顶点开始处理,选择权值最小且没有被访问过的顶点:
A-C[7],A-G[2],A-B[5]==>{A,G}
-
从{A,G}开始,将A,G顶点和它们相邻的还没有访问的顶点进行处理:
A-C[7],A-B[5],G-B[3],G-E[4],G-F[6]==>{A,G,B}
-
从{A,G,B}开始,将A,G,B顶点和它们相邻的还没有访问的顶点进行处理:
A-C[7],G-E[4],G-F[6],B-D[9]==>{A,G,B,E}
-
以此类推,每次找出未被访问过的顶点,并选择权值最小的顶点加入。
第四次:{A,G,B,E}->F,对应边E-F[5];
第五次:{A,G,B,E,F}->D,对应边F-D[4];
第六次:{A,G,B,E,F,D}->C,对应边A-C[7];
-
最终的结果为:{A,G,B,E,F,D,C},权值总和为25;
Prim算法解决修路问题构建图
代码
1 | package com.algorithm.prim; |
运行结果
1 | [10000, 5, 7, 10000, 10000, 10000, 2] |
Prim算法解决修路问题代码实现
代码
1 | package com.algorithm.prim; |
运行结果
1 | 边<A,G> 权值:2 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hey,Joker!
评论
ValineTwikoo