弗洛伊德(Floyd)算法之兩點之間的最短距離問題

1.概述

(1)與迪傑斯特拉(Dijkstra)算法一樣,弗洛伊德(Floyd)算法也是一種用於尋找給定的加權圖中頂點間最短路徑的算法,該算法
名稱以創始人之一、1978 年圖靈獎獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名

2.弗洛伊德(Floyd)算法 與 迪傑斯特拉(Dijkstra)算法 的區別

(1) 弗洛伊德(Floyd)算法:圖中的每一個頂點都是出發頂點,需要求出每一個被看成爲出發頂點的頂點到其他頂點的最短路徑
(2)迪傑斯特拉(Dijkstra)算法:選定圖中某一個頂點作爲出發頂點,求出出發頂點到其他頂點的最短路徑

3.弗洛伊德(Floyd)算法基本思路

(1)設置 i 爲出發頂點,k 爲中間頂點,j 爲其他頂點
(2)設置頂點 vi 到頂點 vk 的最短路徑已知爲 Lik,頂點 vk 到 vj 的最短路徑已知爲 Lkj,頂點 vi 到 vj 的路徑爲 Lij,則 vi 到 vj 的最短路徑爲:min((Lik+Lkj),Lij),vk 的取值爲圖中所有頂點,則可獲得 vi 到 vj 的最短路徑

(3)三層 for 循環解決問題

4.代碼實現

 

package com.zzb.algorithm.floyd;

import java.io.Serializable;
import java.util.Arrays;

/**
 * @Auther: Administrator
 * @Date: 2020/3/30 14:46
 * @Description: 弗洛伊德算法
 */
public class Floyd {
    public static void main(String[] args) {
        // 頂點值數組
        String[] vertexArray = {"A", "B", "C", "D", "E", "F", "G"};
        // 鄰接矩陣
        final int N = Integer.MAX_VALUE/2; // 表示不可以連接
        int[][] matrix = new int[vertexArray.length][vertexArray.length];
        matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
        matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
        matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
        matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
        matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
        matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
        matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
        // 創建圖對象
        Graph graph = new Graph(vertexArray, matrix);

        // 詳細展示最短距離數據
        graph.showDistanceDetail();
    }
}

/**
 * 圖類
 */
class Graph implements Serializable {
    private static final long serialVersionUID = -4402590218398745596L;

    // 存儲圖中各個頂點的集合
    private String[] vertexArray;
    // 存儲圖中各條邊的鄰接矩陣,也作爲保存各個頂點作爲出發頂點到其他頂點的最短距離的數組
    private int[][] edgeArray;
    // 存儲各個頂點的前驅頂點,即通過哪個頂點到達該頂點
    private int[][] pre;

    /**
     * 構造器初始化
     * @param vertexArray 頂點集合
     * @param edgeArray 邊集合
     */
    public Graph(String[] vertexArray, int[][] edgeArray) {
        this.vertexArray = vertexArray;
        this.edgeArray = edgeArray;
        // 初始化其他頂點的前驅頂點
        // A->A,A->B,A->C,A->D,A->E,A->F,A->G
        // A,B,C,D,E,F,G 的前驅頂點都初始化爲A
        // B->A,B->B,B->C,B->D,B->E,B->F,B->G
        // A,B,C,D,E,F,G 的前驅頂點都初始化爲B
        // ...如此類推,用對應索引 i 來表示前驅頂點
        this.pre = new int[this.edgeArray.length][this.edgeArray[0].length];
        for(int i = 0; i < this.vertexArray.length; i++) {
            Arrays.fill(pre[i],i);
        }
    }

    /**
     * 弗洛伊德算法
     */
    private void floyd() {
        // 中間頂點
        for(int k = 0; k < this.vertexArray.length; k++) {
            // 被看成爲出發點的每一個頂點
            for(int i = 0; i < this.vertexArray.length; i++) {
                // 其他頂點
                for(int j = 0; j < this.vertexArray.length; j++) {
                    if(this.edgeArray[i][k] + this.edgeArray[k][j] < this.edgeArray[i][j]) {
                        // 更新出發點到其他頂點的最短距離
                        this.edgeArray[i][j] = this.edgeArray[i][k] + this.edgeArray[k][j];
                        // 更新 j 的前驅頂點
                        this.pre[i][j] = this.pre[k][j];
                    }
                }
            }
        }
    }

    /**
     * 詳細展示最短距離數據
     */
    public void showDistanceDetail() {
        // 弗洛伊德算法
        floyd();

        // 後續處理,詳細展示最短距離數據
        int tempIndex;
        String tempStr = "";
        // 最短距離數組
        for(int i = 0; i < this.vertexArray.length; i++) {
            for(int j = 0; j < this.vertexArray.length; j++) {
                // 比如,A(i)->D(j) 的最短距離所走過的頂點分析,看上面的圖來分析,如下:
                // (1)找到A(i)->D(j)的前驅爲F(5),pre[i][tempIndex] == 5,
                // (2)再找A(i)->F(5)的前驅爲G(6),pre[i][tempIndex] == 6,
                // (3)再找到A(i)->G(6)前驅爲A(i),pre[i][tempIndex] == 1,
                // (4)前驅爲 i(即出發頂點的下標索引) ,終止路徑尋找,得到兩點之間最短距離所走過的頂點
                tempIndex = j;
                while(this.pre[i][tempIndex] != i) {
                    tempIndex = this.pre[i][tempIndex];
                    tempStr = this.vertexArray[tempIndex] + "->" + tempStr;
                }
                // 拼接
                tempStr = this.vertexArray[i] + "->" + tempStr + this.vertexArray[j];
                System.out.print(this.vertexArray[i] + "到" + this.vertexArray[j] + "的最短距離爲" + this.edgeArray[i][j]
                        + "(" + tempStr + ")" + "\t\t\t\t" + "| ");
                // 清空
                tempStr = "";
            }
            System.out.println();
        }
    }
}

5.代碼運行的最終結果(點擊放大查看)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章