1. 程式人生 > 其它 >弗洛伊德演算法

弗洛伊德演算法

基本介紹

Floyd演算法又稱為插點法,是一種利用動態規劃的思想尋找給定的加權圖中多源點之間最短路徑的演算法,與Dijkstra演算法類似。該演算法名稱以創始人之一、1978年圖靈獎獲得者、斯坦福大學計算機科學系教授羅伯特·弗洛伊德命名。

思路

1,從任意一條單邊路徑開始。所有兩點之間的距離是邊的權,如果兩點之間沒有邊相連,則權為無窮大。
2,對於每一對頂點 u 和 v,看看是否存在一個頂點 w 使得從 u 到 w 再到 v 比已知的路徑更短。如果是更新它。
把圖用鄰接矩陣G表示出來,如果從Vi到Vj有路可達,則G[i][j]=d,d表示該路的長度;否則G[i][j]=無窮大。定義一個矩陣D用來記錄所插入點的資訊,D[i][j]表示從Vi到Vj需要經過的點,初始化D[i][j]=j。把各個頂點插入圖中,比較插點後的距離與原來的距離,G[i][j] = min( G[i][j], G[i][k]+G[k][j] ),如果G[i][j]的值變小,則D[i][j]=k。在G中包含有兩點之間最短道路的資訊,而在D中則包含了最短通路徑的資訊。

優缺點分析

Floyd演算法適用於APSP(All Pairs Shortest Paths,多源最短路徑),是一種動態規劃演算法,稠密圖效果最佳,邊權可正可負。此演算法簡單有效,由於三重迴圈結構緊湊,對於稠密圖,效率要高於執行|V|次Dijkstra演算法,也要高於執行|V|次SPFA演算法。
優點:容易理解,可以算出任意兩個節點之間的最短距離,程式碼編寫簡單。
缺點:時間複雜度比較高,不適合計算大量資料。

程式碼

import java.util.Arrays;

public class FloydAlgorithm {
  public static void main(String[] args) {
    char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
    //建立鄰接矩陣
    int[][] matrix = new int[vertex.length][vertex.length];
    final int N = 65535;
    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(matrix, vertex);
    graph.floyd();
    graph.show();
  }
}

class Graph {
  char[] vertex;  //存放頂點
  int[][] dis;  //各個頂點到其它頂點的距離
  int[][] pre;  //到達各個頂點的前驅頂點

  public Graph(int[][] dis,char[] vertex) {
    int length = vertex.length;
    this.vertex = new char[length];
    System.arraycopy(vertex, 0, this.vertex, 0, vertex.length);
    this.dis = new int[length][length];
    for (int i = 0; i < length; i++) {
      System.arraycopy(dis[i], 0, this.dis[i], 0, length);
    }
    this.pre=  new int[length][length];
    for (int i = 0; i < length; i++) {
      Arrays.fill(this.pre[i],i);
    }
  }

  /**
   * 顯示結果
   */
  public void show() {
    for (int i = 0; i < dis.length; i++) {
      for (int j = 0; j < dis.length; j++) {
        System.out.print(pre[i][j] + "\t");
      }
      System.out.println();
      for (int k = 0; k < dis.length; k++) {
        System.out.print("(" + vertex[i] + "到" + vertex[k] + "的最短距離是:" + dis[i][k] + ")");
      }
      System.out.println();
    }
  }

  /**
   * 弗洛伊德演算法
   */
  public void floyd() {
    int length;
    for (int i = 0; i < dis.length; i++) {
      for (int j = 0; j < dis.length; j++) {
        for (int k = 0; k < dis.length; k++) {
          length = dis[j][i] + dis[i][k];
          if (length < dis[j][k]) {
            dis[j][k] = length;
            pre[j][k] = pre[i][k];
          }
        }
      }
    }
  }

}