原文: https://www.programiz.com/dsa/floyd-warshall-algorithm

在本教程中,您将学习 floyd-warshall 算法的工作原理。 此外,您还将找到 C,C++ ,Java 和 Python 中的 floyd-warshall 算法的工作示例。

Floyd-Warshall 算法是一种用于找到加权图中所有顶点对之间的最短路径的算法。 该算法适用于有向和无向加权图。 但是,它不适用于周期为负的图(周期中边的总和为负)。

加权图是其中每个边都有与之关联的数值的图。

Floyd-Warhshall 算法也称为 Floyd 算法,Roy-Floyd 算法,Roy-Warshall 算法或 WFI 算法。

该算法遵循动态规划方法来找到最短路径。


Floyd-Warshall 算法如何工作?

让给定的图形为:

Floyd-Warshall 算法 - 图1

初始图

请按照以下步骤查找所有顶点对之间的最短路径。

  1. 创建大小为n*n的矩阵A^1,其中n是顶点数。 行和列的索引分别为ijij是图形的顶点。
    每个单元格A[i][j]填充了从第i个顶点到第j个顶点的距离。 如果没有从第i个顶点到第j个顶点的路径,则该单元将保留为无穷大。
    Floyd-Warshall 算法 - 图2
    用第i个顶点与第j个顶点之间的距离填充每个单元格

  2. 现在,使用矩阵A^0创建一个矩阵A^1。 第一列和第一行中的元素保持原样。 其余单元格按以下方式填充。
    k为从源到目标的最短路径中的中间顶点。 在此步骤中,k是第一个顶点。A[i][j]填充有(A[i][k] + A[k][j]) if (A[i][j] > A[i][k] + A[k][j])
    也就是说,如果从源到目的地的直接距离大于通过顶点k的路径,则单元格将填充A[i][k] + A[k][j]
    在此步骤中,k为顶点 1。我们计算通过此顶点k从源顶点到目标顶点的距离。
    Floyd-Warshall 算法 - 图3
    计算通过此顶点k从源顶点到目的顶点的距离
    例如:对于A^1[2, 4],从顶点 2 到 4 的直接距离是 4 并且从顶点 2 到 4 到顶点(即从顶点 2 到 1 和从顶点 1 到 4)的距离之和为 7。由于4 < 7A^0[2, 4]用 4 填充。

  3. 类似地,使用A^3创建A^2。 第二列和第二行中的元素保持原样。
    在此步骤中,k是第二个顶点(即顶点 2)。 其余步骤与步骤 2 中的步骤相同。
    Floyd-Warshall 算法 - 图4
    计算通过此顶点 2 从源顶点到目标顶点的距离

  4. 同样,还创建了A^3A^4
    Floyd-Warshall 算法 - 图5
    计算通过此顶点从源顶点到目标顶点的距离

    Floyd-Warshall 算法 - 图6
    计算通过定点 4 从源顶点到目标顶点的距离。

  5. A^4给出每对顶点之间的最短路径。


Floyd-Warshall 算法

  1. n = no of vertices
  2. A = matrix of dimension n*n
  3. for k = 1 to n
  4. for i = 1 to n
  5. for j = 1 to n
  6. Ak[i, j] = min (Ak-1[i, j], Ak-1[i, k] + Ak-1[k, j])
  7. return A

Python,Java 和 C/C++ 示例

  1. # Floyd Warshall Algorithm in python
  2. # The number of vertices
  3. nV = 4
  4. INF = 999
  5. # Algorithm implementation
  6. def floyd_warshall(G):
  7. distance = list(map(lambda i: list(map(lambda j: j, i)), G))
  8. # Adding vertices individually
  9. for k in range(nV):
  10. for i in range(nV):
  11. for j in range(nV):
  12. distance[i][j] = min(distance[i][j], distance[i][k] + distance[k][j])
  13. print_solution(distance)
  14. # Printing the solution
  15. def print_solution(distance):
  16. for i in range(nV):
  17. for j in range(nV):
  18. if(distance[i][j] == INF):
  19. print("INF", end=" ")
  20. else:
  21. print(distance[i][j], end=" ")
  22. print(" ")
  23. G = [[0, 3, INF, 5],
  24. [2, 0, INF, 4],
  25. [INF, 1, 0, INF],
  26. [INF, INF, 2, 0]]
  27. floyd_warshall(G)
  1. // Floyd Warshall Algorithm in Java
  2. class FloydWarshall {
  3. final static int INF = 9999, nV = 4;
  4. // Implementing floyd warshall algorithm
  5. void floydWarshall(int graph[][]) {
  6. int matrix[][] = new int[nV][nV];
  7. int i, j, k;
  8. for (i = 0; i < nV; i++)
  9. for (j = 0; j < nV; j++)
  10. matrix[i][j] = graph[i][j];
  11. // Adding vertices individually
  12. for (k = 0; k < nV; k++) {
  13. for (i = 0; i < nV; i++) {
  14. for (j = 0; j < nV; j++) {
  15. if (matrix[i][k] + matrix[k][j] < matrix[i][j])
  16. matrix[i][j] = matrix[i][k] + matrix[k][j];
  17. }
  18. }
  19. }
  20. printMatrix(matrix);
  21. }
  22. void printMatrix(int matrix[][]) {
  23. for (int i = 0; i < nV; ++i) {
  24. for (int j = 0; j < nV; ++j) {
  25. if (matrix[i][j] == INF)
  26. System.out.print("INF ");
  27. else
  28. System.out.print(matrix[i][j] + " ");
  29. }
  30. System.out.println();
  31. }
  32. }
  33. public static void main(String[] args) {
  34. int graph[][] = { { 0, 3, INF, 5 }, { 2, 0, INF, 4 }, { INF, 1, 0, INF }, { INF, INF, 2, 0 } };
  35. FloydWarshall a = new FloydWarshall();
  36. a.floydWarshall(graph);
  37. }
  38. }
// Floyd-Warshall Algorithm in C

#include <stdio.h>

// defining the number of vertices
#define nV 4

#define INF 999

void printMatrix(int matrix[][nV]);

// Implementing floyd warshall algorithm
void floydWarshall(int graph[][nV]) {
  int matrix[nV][nV], i, j, k;

  for (i = 0; i < nV; i++)
    for (j = 0; j < nV; j++)
      matrix[i][j] = graph[i][j];

  // Adding vertices individually
  for (k = 0; k < nV; k++) {
    for (i = 0; i < nV; i++) {
      for (j = 0; j < nV; j++) {
        if (matrix[i][k] + matrix[k][j] < matrix[i][j])
          matrix[i][j] = matrix[i][k] + matrix[k][j];
      }
    }
  }
  printMatrix(matrix);
}

void printMatrix(int matrix[][nV]) {
  for (int i = 0; i < nV; i++) {
    for (int j = 0; j < nV; j++) {
      if (matrix[i][j] == INF)
        printf("%4s", "INF");
      else
        printf("%4d", matrix[i][j]);
    }
    printf("\n");
  }
}

int main() {
  int graph[nV][nV] = {{0, 3, INF, 5},
             {2, 0, INF, 4},
             {INF, 1, 0, INF},
             {INF, INF, 2, 0}};
  floydWarshall(graph);
}
// Floyd-Warshall Algorithm in C++

#include <iostream>
using namespace std;

// defining the number of vertices
#define nV 4

#define INF 999

void printMatrix(int matrix[][nV]);

// Implementing floyd warshall algorithm
void floydWarshall(int graph[][nV]) {
  int matrix[nV][nV], i, j, k;

  for (i = 0; i < nV; i++)
    for (j = 0; j < nV; j++)
      matrix[i][j] = graph[i][j];

  // Adding vertices individually
  for (k = 0; k < nV; k++) {
    for (i = 0; i < nV; i++) {
      for (j = 0; j < nV; j++) {
        if (matrix[i][k] + matrix[k][j] < matrix[i][j])
          matrix[i][j] = matrix[i][k] + matrix[k][j];
      }
    }
  }
  printMatrix(matrix);
}

void printMatrix(int matrix[][nV]) {
  for (int i = 0; i < nV; i++) {
    for (int j = 0; j < nV; j++) {
      if (matrix[i][j] == INF)
        printf("%4s", "INF");
      else
        printf("%4d", matrix[i][j]);
    }
    printf("\n");
  }
}

int main() {
  int graph[nV][nV] = {{0, 3, INF, 5},
             {2, 0, INF, 4},
             {INF, 1, 0, INF},
             {INF, INF, 2, 0}};
  floydWarshall(graph);
}

Floyd Warshall 算法复杂度

时间复杂度

有三个循环。 每个循环具有恒定的复杂度。 因此,Floyd-Warshall 算法的时间复杂度为O(n^3)

空间复杂度

Floyd-Warshall 算法的空间复杂度为O(n^2)


Floyd Warshall 算法应用

  • 找到有向图的最短路径
  • 查找有向图的传递闭包
  • 查找实矩阵的逆
  • 测试无向图是否是二分图