Floyd-Warshall算法求解所有结点对的最短路径问题Java和Python实现

本文介绍了一种用于解决所有结点对之间最短路径问题的高效算法——Floyd-Warshall算法,并通过Java和Python代码实现了该算法。与Bellman-Ford算法和Dijkstra算法相比,该算法基于邻接矩阵,适用于密集图。

其实求解所有结点对之间的最短路径问题完全可以用调用|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()

 

1-18 求解最短路径-作业 分数 100 作者 魏峻 单位 陕西理工大学 最短路径论研究中的一个经典算法问题, 旨在寻找(由结点路径组成的)中两结点之间最短路径。用于解决最短路径问题算法被称做“最短路径算法”, 有时被简称作“路径算法”。 最常用的路径算法有: Dijkstra算法 Floyd算法\Floyd-Warshall算法 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。 Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权中多源点之间最短路径算法,与Dijkstra算法类似。 1.jpg 输入格式: 在第1行输入的类型,0表示无向,1表示有向。例如:1。 在第2行输入的顶点个数 N 弧数 E,用空格隔开。例如:18 38。 在第3行输入的顶点元素,用空格隔开,顶点类型用整型表示。例如:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17。 后面 E 行,分别输入每条弧的两个顶点及其权值,用空格隔开。例如:0 1 8 表示顶点 0到顶点 1 的弧,权值为 8。以此类推。注:如果是无向,相同的弧不重复输入。 最后一行输入要计算最短路径的源点终点的顶点。例如:0 17 输出格式: 输出Dijkstra算法求解源点到终点的最短路径。 输出Dijkstra算法求解源点到终点最短路径经过的所有节点,用空格隔开。 输出Dijkstra算法求解的源点到其他所有节点最短路径,用空格隔开。 空一行。 输出Floyd算法求解源点到终点的最短路径。 输出Floyd算法求解源点到终点最短路径经过的所有节点,用空格隔开。 输出Floyd算法求解的所有节点之间最短路径,按矩阵输出,每个值占3个字符。 输入样例: 1 18 38 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 8 0 14 3 1 4 1 2 3 2 2 6 1 2 5 7 3 2 4 4 0 4 4 5 2 5 6 4 5 8 4 5 9 3 6 2 1 6 5 2 7 0 2 7 14 6 8 4 2 8 5 8 8 11 7 9 5 2 9 13 3 10 17 4 11 7 8 11 8 1 11 12 1 12 8 7 12 9 5 12 11 4 12 16 3 14 11 5 15 11 1 15 14 5 16 13 2 16 15 3 16 17 8 17 10 6 17 13 3 17 16 8 0 17 输出样例: 20 0 14 11 12 16 17 0 8 16 18 9 11 15 16 9 14 26 8 9 14 3 15 12 20 20 0 14 11 12 16 17 # 8 16 18 9 11 15 16 9 14 26 8 9 14 3 15 12 20 5 # 8 10 1 3 7 21 7 6 31 13 14 9 8 20 17 25 13 21 # 2 9 3 1 22 7 6 32 14 15 9 16 21 18 26 17 25 4 # 13 7 5 26 11 10 36 18 19 13 20 25 22 30 4 12 7 9 # 2 6 20 6 5 30 12 13 8 7 19 16 24 10 18 5 7 6 # 4 19 4 3 29 11 12 6 13 18 15 23 12 20 1 3 8 2 # 21 6 5 31 13 14 8 15 20 17 25 2 10 18 20 11 13 17 # 11 16 28 10 11 16 5 17 14 22 6 14 9 11 2 4 8 15 # 7 25 7 8 10 9 14 11 19 12 20 7 9 8 2 6 21 6 # 31 13 14 3 15 20 17 25 23 31 26 28 19 21 25 24 17 22 # 16 17 7 20 15 12 4 7 15 10 12 3 5 9 8 1 6 18 # 1 6 10 7 4 12 11 19 12 14 7 7 11 12 5 5 17 4 # 5 11 6 3 11 # # # # # # # # # # # # # # # # # # 12 20 15 17 8 10 14 13 6 11 23 5 6 11 # 12 9 17 8 16 11 13 4 6 10 9 2 7 19 1 2 7 5 # 5 13 11 19 14 16 7 9 13 12 5 10 14 4 5 2 8 3 # 8 19 27 22 24 15 17 21 20 13 18 6 12 13 3 16 11 8 # 程序框架(部分): #include <iostream> #include <iomanip> #define MaxInt 32767 #define MVNum 100 //最大顶点数 #define OK 1 #define ERROR 0 #define OVERFLOW -2 using namespace std; //------------的邻接矩阵----------------- typedef struct { int vexs[MVNum]; //顶点表 int arcs[MVNum][MVNum]; //邻接矩阵 int vexnum,arcnum; //的当前点数边数 }AMGraph; int *D = new int[MVNum]; //用于记录最短路的长度 bool *S = new bool[MVNum]; //标记顶点是否进入S集合 int *Path = new int[MVNum]; //用于记录最短路顶点的前驱 int Path_F[MVNum][MVNum]; //最短路径上顶点vj的前一顶点的序号 int D_F[MVNum][MVNum]; //记录顶点vivj之间最短路径长度 //函数声明 int LocateVex(AMGraph G , int v); //定位顶点(已知) int CreateAMGraph(AMGraph &G); //创建有权网(已知) void ShortestPath_DIJ(AMGraph G, int v0); //算法6.10 Dijkstra算法有向网G的v0顶点到其余顶点的最短路径 void ShortestPath_Floyed(AMGraph G); //算法6.11 用Floyd算法有向网G中各对顶点ij之间最短路径 void PrintPath(AMGraph G , int vstart ,int vend ); //输出Dijkstra算法最短路径 void PrintPath_F(AMGraph G , int vstart ,int vend ); //输出Floyd算法最短路径 //主函数 int main() { AMGraph G; int num_vstart, num_vend; int vstart, vend; CreateAMGraph(G); cin >> vstart >> vend; num_vstart = LocateVex(G, vstart); num_vend = LocateVex(G, vend); //迪杰斯特拉算法 ShortestPath_DIJ(G, num_vstart); cout << D[num_vend] << endl; PrintPath(G, num_vstart, num_vend); cout << G.vexs[num_vend] << endl; //源点0到各顶点的最短路径 for(int i = 0; i < G.vexnum - 1; i++) cout << D[i] << " "; cout << D[G.vexnum - 1] << endl << endl; //弗洛伊德算法; ShortestPath_Floyed(G); cout << D_F[vstart][vend] << endl; PrintPath_F(G, num_vstart, num_vend); cout << G.vexs[num_vend] << endl; //各顶点之间最短路径 for(int i = 0; i < G.vexnum; i++) { for(int j = 0; j < G.vexnum; j++) if(D_F[i][j] == MaxInt) cout << setw(3) << '#'; else cout << setw(3) << D_F[i][j]; cout << endl; } } /* 补全所有子函数 */ 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB
最新发布
11-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值