学习数据结构笔记(20) --- [普利姆算法(PrimAlgorithm) 由村庄的修路问题找最短权值引入]
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习数据结构笔记(20) --- [普利姆算法(PrimAlgorithm) 由村庄的修路问题找最短权值引入]相关的知识,希望对你有一定的参考价值。
B站学习传送门–>尚硅谷Java数据结构与java算法(Java数据结构与算法)
情景引入
假设现有7个村庄准备修公路,怎么样选择,才能让修路的里程最短并且连通所有的村庄?
直接连通的话,可能权值就比较大了;
那么这道题目其实可以转换为求解构建最小生成树的问题;
最小生成树:
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
克鲁斯卡尔算法将在本篇之后进行学习,本次学习使用普利姆算法解决这个问题;
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。
步骤分析
由普利姆算法求解最小生成树时,最终需要对n个结点生成n-1条边即可;且为极小连通子图;
具体过程:
定义连通图G:(V,E), 最小生成树:T:(U,D),
从连通图G的第一个顶点出发,找到权值最小的路径,放入最小生成树中,将这个路径连接的结点标记为已访问,
然后这两个顶点分别出发,找路径最短的,…重复操作;直到将连通图中的顶点全部访问;
图解过程:
(1)比如,先找到第一个村庄A, 对路径AB5
,AC7
,AG2
比较后发现AG
最短,则将A村庄与G村庄连通;此时A和G标记为已访问结点
然后,这时的出发点就是A点和G点了
(2) 比较路径 AB5
,AC7
,GB2
,GE4
,GF6
后,找到最短路径GB
.将G村庄与B村庄连通; B村庄标记为已访问结点;
这时出发点就是A点,B点,G点;
(3)比较路径AC7
,GE4
,GF6
,BD9
后,找到最短路径GE
,将G村庄与E村庄连通,且将E村庄标记为已访问结点;
这时出发点是A点,B点,G点,E点;
(4) 比较路径AC7
,GF6
,BD9
,EC8
,EF5
后,找到最短路径EF
,将F村庄与E村庄连通,且将F村庄标记为已访问结点;
这时出发点就是A点,B点,G点,E点,F点;
(5)比较路径AC7
,BD9
,EC8
,FD4
后,找到最短路径FD
,将村庄D与F村庄连通,且将D村庄标记为已访问结点;
这时出发点就是A点,B点,G点,E点,F点,D点;
(6)比较路径AC7
,EC8
后,找到最短路径AC
,将村庄C与A连通,C村庄标记为已访问结点;
修路结束;得到最短路径25
具体实现
/**
* @author by CSDN@小智RE0
* @date 2021-12-07
* 普利姆算法
*/
public class PrimAlgorithm
public static void main(String[] args)
//构建村庄修路问题的图;
char[] village = 'A', 'B', 'C', 'D', 'E', 'F', 'G';
//村庄的个数;
int size = village.length;
//手动构建村庄之间的连接权值邻接矩阵;
int[][] villagePrimitive
= Integer.MAX_VALUE, 5, 7, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 2,
5, Integer.MAX_VALUE, Integer.MAX_VALUE, 9, Integer.MAX_VALUE, Integer.MAX_VALUE, 3,
7, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 8, Integer.MAX_VALUE, Integer.MAX_VALUE,
Integer.MAX_VALUE, 9, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 4, Integer.MAX_VALUE,
Integer.MAX_VALUE, Integer.MAX_VALUE, 8, Integer.MAX_VALUE, Integer.MAX_VALUE, 5, 4,
Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 4, 5, Integer.MAX_VALUE, 6,
2, 3, Integer.MAX_VALUE, Integer.MAX_VALUE, 4, 6, Integer.MAX_VALUE;
//查看初始化的数据;
Graph graph = new Graph(size);
MST mst = new MST();
mst.getMST(size, graph, village, villagePrimitive);
mst.printGraph(graph);
//进行最短路径计算;
mst.primAlgorithm(graph, 0);
//基础的图;
class Graph
//顶点;
public char[] node;
//路径权值;
public int[][] weight;
//顶点个数;
public int size;
//初始化;size:节点个数;
public Graph(int size)
this.node = new char[size];
this.weight = new int[size][size];
this.size = size;
//最小生成树;
class MST
/**
* 生成最小树
* @param size 图的节点个数
* @param graph 构建的图
* @param node 顶点
* @param weight 权值
*/
public void getMST(int size, Graph graph, char[] node, int[][] weight)
for (int i = 0; i < size; i++)
graph.node[i] = node[i];
System.arraycopy(weight[i], 0, graph.weight[i], 0, size);
/**
* 简易的普利姆算法;在当前节点为出发点找到的最小权值边路径,且进行路径打印;
* @param graph 当前问题的图
* @param index 当前的节点索引
*/
public void primAlgorithm(Graph graph, int index)
//定义一个访问数组;
boolean[] isVisited = new boolean[graph.size];
//当前点先给他标记已访问;
isVisited[index] = true;
//两个要连通的节点 start,end
int start = -1;
int end = -1;
//最短的路径;
int minPath = Integer.MAX_VALUE;
//最终的路径和;
int total = 0;
//最终会走6次;
for (int i = 1; i < graph.size; i++)
for (int j = 0; j < graph.size; j++)
for (int k = 0; k < graph.size; k++)
//要找的是没有访问的;
if (isVisited[j] && !isVisited[k] && minPath > graph.weight[j][k])
minPath = graph.weight[j][k];
start = j;
end = k;
System.out.println("当前路径" + graph.node[start] + "-->" + graph.node[end] + "权值为->" + minPath);
//最终路径和拼接;
total += minPath;
//最终把符合的节点置为已访问;
isVisited[end] = true;
//最短路径重置;
minPath = Integer.MAX_VALUE;
System.out.println("最终的方案,最短路径为-->"+total);
/**
* 打印图的邻接矩阵
*
* @param graph 图
*/
public void printGraph(Graph graph)
for (int[] weight : graph.weight)
System.out.println(Arrays.toString(weight));
测试结果
[2147483647, 5, 7, 2147483647, 2147483647, 2147483647, 2]
[5, 2147483647, 2147483647, 9, 2147483647, 2147483647, 3]
[7, 2147483647, 2147483647, 2147483647, 8, 2147483647, 2147483647]
[2147483647, 9, 2147483647, 2147483647, 2147483647, 4, 2147483647]
[2147483647, 2147483647, 8, 2147483647, 2147483647, 5, 4]
[2147483647, 2147483647, 2147483647, 4, 5, 2147483647, 6]
[2, 3, 2147483647, 2147483647, 4, 6, 2147483647]
当前路径A-->G权值为->2
当前路径G-->B权值为->3
当前路径G-->E权值为->4
当前路径E-->F权值为->5
当前路径F-->D权值为->4
当前路径A-->C权值为->7
最终的方案,最短路径为-->25
以上是关于学习数据结构笔记(20) --- [普利姆算法(PrimAlgorithm) 由村庄的修路问题找最短权值引入]的主要内容,如果未能解决你的问题,请参考以下文章