其实求解所有结点对之间的最短路径问题完全可以用调用|V|次Bellman-Ford算法或Dijkstra算法来实现,但是那样肯定效率会比较低下。与前面两个算法基于邻接链表不同,本文所要说的Floyd-Warshall算法是基于邻接矩阵的,当然也可以用邻接链表来实现。
假设i与j是图中的两个结点,那么它们之间至多经过k个结点的最短路径代价肯定不小于至多经过k+1个结点的最短路径的代价。由此对于所有结点对最短路径问题我们有如下递归解:
《算法导论》书中给出的算法伪代码如下:
而下面是一个运用Floyd-Warshall算法求解的过程的一个例子,其中左边矩阵记录的是当前的最短路径值,右边矩阵则是当前的前驱节点。
由此用Java代码实现如下
package Floyed_Warshall;
import java.util.ArrayList;
import java.util.List;
public class Main {
private static int INF=Integer.MAX_VALUE;
private int[][] dist;
private List<Integer> result=new ArrayList<>();
public static void main(String[] args) {
Main graph=new Main(5);
int[][] matrix={
{0,3,8,INF,-4},
{INF,0,INF,1,7},
{INF,4,0,INF,INF},
{2,INF,-5,0,INF},
{INF,INF,INF,6,0},
};
graph.floyd(matrix);
System.out.println("============最短路径长度============");
for(int i = 0;i<graph.dist.length;i++){
for(int j = 0;j<graph.dist[i].length;j++)
System.out.print(graph.dist[i][j]+" ");
System.out.println();
}
}
public void floyd(int[][] matrix){
int size=matrix.length;
for(int i=0;i< size;i++){
for(int j=0;j< size;j++){
dist[i][j]=matrix[i][j];
}
}
for(int k=0;k< size;k++){
for(int i=0;i< size;i++){
for(int j=0;j< size;j++){
if(dist[i][k]!=INF&&
dist[k][j]!=INF&&
dist[i][k]+dist[k][j]< dist[i][j]){
dist[i][j]=dist[i][k]+dist[k][j];
}
}
}
}
}
public Main(int size){
this.dist=new int[size][size];
}
}
运行结果截图如下
下面是一个Python版本的代码
import numpy as np
"""
使用Floyed-Warshall算法计算最短路径距离
输入是一个初始的距离矩阵
@author: sdu_brz
@date: 2019/02/27
"""
def floyed(distance0):
"""
计算所有顶点对的最短路径距离
:param distance0: 初始的距离矩阵
:return: 保存了最短路径长度的矩阵
"""
data_shape = distance0.shape
n = data_shape[0]
distance = distance0.copy()
for index in range(0, n):
for i in range(0, n):
for j in range(0, n):
if distance[i, index] < float('inf') and distance[index, j] < float('inf') and distance[i, index]+distance[index, j]<distance[i, j]:
distance[i, j] = distance[i, index] + distance[index, j]
return distance
def test():
M = np.array([[0, 3, 8, float('inf'), -4],
[float('inf'), 0, float('inf'), 1, 7],
[float('inf'), 4, 0, float('inf'), float('inf')],
[2, float('inf'), -5, 0, float('inf')],
[float('inf'), float('inf'), float('inf'), 6, 0]])
distance = floyed(M)
print(distance)
if __name__ == '__main__':
test()