多源最短路径算法—Floyd算法[短小精悍]

前言

图论中,在寻路最短路径中除了Dijkstra算法之外,还有Floyd算法也是很是经典,然而两种算法仍是有区别的,Floyd主要计算多源最短路径。java

在单源正权值最短路径,咱们会用Dijkstra算法来求最短路径,而且算法的思想很简单——贪心算法:每次肯定最短路径的一个点而后维护(更新)这个点周围点的距离加入预选队列,等待下一次的抛出肯定。可是虽然思想很简单,实现起来是很是复杂的,咱们须要邻接矩阵(表)储存长度,须要优先队列(或者每次都比较)维护一个预选点的集合。还要用一个boolean数组标记是否已经肯定、还要---------算法

总之,Dijkstra算法的思想上是很容易接受的,可是实现上实际上是很是麻烦的。可是单源最短路径没有更好的办法。复杂度也为O(n2)数组

而在n节点多源最短路径中,若是从Dijkstra算法的角度上,只须要将Dijkstra封装,而后执行n次Dijkstra算法便可,复杂度为O(n3)。可是这样感受很臃肿,代码量巨大,占用不少空间内存。有没有啥方法可以稍微变变口味呢?学习

答案是有的,这就是易写但稍须要理解的Floyd算法。一个求多元最短路径算法。spa

算法介绍

先看看百度百科的定义吧:.net

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法相似。该算法名称以创始人之1、1978年图灵奖得到者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。3d

简单的来讲,算法的主要思想是动态规划(dp),而求最短路径须要不断松弛(熟悉spfa算法的可能熟悉松弛)。code

而算法的具体思想为:cdn

  1. 邻接矩阵dist储存路径,同时最终状态表明点点的最短路径。若是没有直接相连的两点那么默认为一个很大的值(不要溢出)!而本身的长度为0.
  2. 第1个到第n个点依次加入图中。每一个点加入进行试探是否有路径长度被更改。
  3. 而上述试探具体方法为遍历图中每个点(i,j双重循环),判断每个点对距离是否由于加入的点而发生最小距离变化。若是发生改变,那么两点(i,j)距离就更改。
  4. 重复上述直到最后插点试探完成。

其中第三步的状态转移方程为:blog

  • dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]) 其中dp[x][y]的意思能够理解为x到y的最短路径。因此dp[i][k]的意思能够理解为i到k的最短路径dp[k][j]的意思能够理解为k到j的最短路径.

我们图解一个案例:

在这里插入图片描述
默认的最短长度初始为邻接矩阵初始状态

  • 加入第一个节点1,你们能够发现,因为1的加入,使得原本不连通的2,3点对和2,4点对变得联通,而且加入1后距离为当前最小。(能够很直观加入5以后2,4,更短可是还没加入)。为了更好的描述其实此时的直接联通点多了两条。(2,3)和(2,4).咱们在dp中无论这个结果是经过前面那些步骤来的,可是在这个状态,这两点的最短距离就算它!
    在这里插入图片描述
  • 同时你能够发现加入1其中也使得3,1,4这样联通,可是 3,1,4联通的话距离为9远远大于原本的(3,4)为2,因此不进行更新。
  • 我们继续加入第二个节点。在加入的初始态为:
    在这里插入图片描述
  • 进行遍历插入看看是否更新节点
    在这里插入图片描述
    实际上这个时候图中的连线就比较多了。固然这些连线都是表明当前的最短路径。 这也和咱们的需求贴合,咱们最终要的是全部节点的最短路径。每一个节点最终都应该有6条指向不一样节点的边! 表示邻接矩阵的最终结果。

至于算法的模拟两部核心已经告诉你们了,你们能够自行模拟剩下的。

程序实现

而对于程序而言,这个插入的过程至关简单。核心代码只有四行! 代码以下

public class floyd {
	static int max = 66666;// 别Intege.max 两个相加越界为负
	public static void main(String[] args) {
		int dist[][] = {
				{ 0, 2, 3, 6, max, max }, 
				{ 2, 0, max, max,4, 6 }, 
				{ 3, max, 0, 2, max, max },
				{ 6, max, 2, 0, 1, 3 }, 
				{ max, 4, max, 1, 0, max }, 
				{ max, 6, max, 3, max, 0 } };// 地图
		// 6个
		for (int k = 0; k < 6; k++)// 加入滴k个节点
		{
			for (int i = 0; i < 6; i++)// 松弛I行
			{
				for (int j = 0; j < 6; j++)// 松弛i列
				{
					dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
				}
			}
		}
		// 输出
		for (int i = 0; i < 6; i++) {
			System.out.print("节点"+(i+1)+" 的最短路径");
			for (int j = 0; j < 6; j++) {
				System.out.print(dist[i][j]+" ");
			}
			System.out.println();
		}
	}
}

复制代码

结果为:

在这里插入图片描述
能够自行计算, 图和上篇的Dijkstra是一致的,你们能够自行比对,结果一致,说明咱么的结果成功的。

固然,在你学习的过程当中,能够在每加入一个节点插入完成后,打印邻接矩阵的结果,看看前两部和笔者的是否相同(有助于理解),若是相同,则说明正确!

你可能还会有疑惑,那咱么就用一个局部性来演示一下,看其中AB最短距离变化状况祝你理解:

在这里插入图片描述

好啦,Floyd算法就介绍到这里,若是对你有帮助,请动动小手点个赞吧!蟹蟹。 但愿和各位共同进步!欢迎关注笔者公众号:bigsai!

相关文章
相关标签/搜索