最短路徑之弗洛伊德算法


下圖左部分是一個最簡單的3個頂點連通網圖。

先定義兩個數組D[3][3]和P[3][3],D代表頂點到頂點的最短路徑權值和的矩陣,P代表對應頂點的最小路徑的前驅矩陣。在未分析任何頂點之前,我們將D命名為D-1  ,其實它就是初始的圖的鄰接矩陣。將P命名為P-1 ,初始化為圖中所示的矩陣。
    首先,我們來分析,所有的頂點經過v0后到達另一頂點的最短距離。因為只有三個頂點,因此需要查看v1->v0->v2,得到D-1 [1][0] + D-1 [0][2] = 2 + 1 = 3。D-1 [1][2]表示的是v1->v2的權值是5,我們發現D-1 [1][2] > D-1 [1][0] + D-1 [0][2],通俗的講就是v1->v0->v2比直接v1->v2距離還要近。所以我們就讓D-1 [1][2]  = D-1 [1][0] + D-1 [0][2],同樣的D-1 [2][1]  = 3,於是就有了D的矩陣。因為有了變化,所以P矩陣對應的P-1[1][2]和P-1[2][1]也修改為當前中轉的頂點v0的下標0,於是就有了P0。也就是說:
    --->動態規划乎
    接下來,其實也就是在D0和P0的基礎上,繼續處理所有頂點經過v1和v2后到達另一頂點的最短路徑,得到D1和P1、D2和P2完成所有頂點到所有頂點的最短路徑的計算。
    首先我們針對下圖的左網圖准備兩個矩陣D-1和P-1,就是網圖的鄰接矩陣,初設為P[j][j] = j這樣的矩陣,它主要用來存儲路徑。

接下來,其實也就是在D0和P0的基礎上,繼續處理所有頂點經過v1和v2后到達另一頂點的最短路徑,得到D1和P1、D2和P2完成所有頂點到所有頂點的最短路徑的計算。
    首先我們針對下圖的左網圖准備兩個矩陣D-1和P-1,就是網圖的鄰接矩陣,初設為P[j][j] = j這樣的矩陣,它主要用來存儲路徑。

具體代碼如下:

package com.neuedu.algorithm;

import java.util.ArrayList;
import java.util.List;
public class FloydInGraph {

    private static int INF = Integer.MAX_VALUE;
    private int[][] dist;
    //頂點i 到 j的最短路徑長度,初值是i到j的邊的權重
    private int[][] path;
    private List<Integer> result = new ArrayList<Integer>();

    public static void main(String[] args) {
        FloydInGraph graph = new FloydInGraph(5);
        int[][] matrix = {
                {INF, 30, INF, 10, 50},
                {INF, INF, 60, INF, INF},
                {INF, INF, INF, INF, INF},
                {INF, INF, INF, INF, 30},
                {50, INF, 40, INF, INF},
        };
        int begin=0;
        int end=4;
        graph.findCheapestPath(begin,end,matrix);
        List<Integer> list=graph.result;
        System.out.println(begin+" to "+end+",the cheapest path is:");
        System.out.println(list.toString());
        System.out.println(graph.dist[begin][end]);
    }

    public  void findCheapestPath(int begin,int end,int[][] matrix){
        floyd(matrix);
        result.add(begin);
        findPath(begin,end);
        result.add(end);
    }

    public void findPath(int i,int j){
        // 找到路由節點
        int k=path[i][j];
        if(k==-1)
            return;
        // 從i到路由節點進行遞歸尋找中間節點
        findPath(i,k);
        result.add(k);
        // 從j到路由節點進行遞歸尋找中間節點
        findPath(k,j);
    }
    public  void floyd(int[][] matrix){
        int size=matrix.length;
        for(int i=0;i< size;i++){
            for(int j=0;j< size;j++){
                path[i][j]=-1;
                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]){
                        // 更新i和j兩點間的距離
                        dist[i][j]=dist[i][k]+dist[k][j];
                        // 更新i和j兩點間的路由信息
                        path[i][j]=k;
                    }
                }
            }
        }
    }

    public FloydInGraph(int size){
        this.path=new int[size][size];
        this.dist=new int[size][size];
    }
}

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM