Data Structures Algorithms 简明教程

Floyd Warshall Algorithm

Floyd-Warshall 算法是一种图算法,用于找到加权图中所有顶点之间的最短路径。此算法与其他最短路径算法不同;简单来说,此算法将图中的每个顶点用作枢纽,以检查它是否提供从一点到另一点的最短路径。

Floyd-Warshall 算法适用于有向和无向加权图,除非这些图不包含任何负环。负环是指图中所有边的总和不得导致负数。

由于算法处理重叠的子问题(由充当枢纽的顶点找到的路径存储下来以解决下一步),它使用动态规划方法。

Floyd-Warshall 算法是全对最短路径算法中的一种方法,它使用图的邻接矩阵表示法求解。

Floyd-Warshall Algorithm

考虑一个图, G = {V, E} ,其中 V 是图中存在的所有顶点组成的集合,E 是图中所有边组成的集合。图, G ,以邻接矩阵的形式表示, A ,包含连接两个顶点的每条边的所有权重。

Algorithm

Step 1 − 构造邻接矩阵 A ,其中包含图中存在的边所有成本。如果两个顶点之间没有路径,则将值标记为 ∞。

Step 2 − 从 A 中派生一个 A1 ,同时保持原始邻接矩阵中第一行和第一列在 A1 中的完整性。对于其余值,例如 A1[i,j] ,如果 A[i,j]>A[i,k]+A[k,j] ,则用 A[i,k]+A[k,j] 替换 A1[i,j] 。否则,不更改值。在此步骤中, k = 1 (作为透视点的第一个顶点)。

Step 3 − 通过更改每个透视点顶点的 k 值,对图中所有顶点重复 Step 2 ,直到得到最终矩阵。

Step 4 − 得到的最终邻接矩阵是包含所有最短路径的最终解。

Pseudocode

Floyd-Warshall(w, n){ // w: weights, n: number of vertices
   for i = 1 to n do // initialize, D (0) = [wij]
      for j = 1 to n do{
         d[i, j] = w[i, j];
      }
      for k = 1 to n do // Compute D (k) from D (k-1)
         for i = 1 to n do
            for j = 1 to n do
               if (d[i, k] + d[k, j] < d[i, j]){
                  d[i, j] = d[i, k] + d[k, j];
               }
      return d[1..n, 1..n];
}

Example

考虑以下有向加权图 G = {V, E} 。使用 Floyd-Warshall 算法找到图中所有顶点之间的最短路径。

directed weighted graph

Solution

Step 1

用所有距离作为值构造一个邻接矩阵 A

A=\begin{matrix} 0 & 5& \infty & 6& \infty \\ \infty & 0& 1& \infty& 7\\ 3 & \infty& 0& 4& \infty\\ \infty & \infty& 2& 0& 3\\ 2& \infty& \infty& 5& 0\\ \end{matrix}

Step 2

将上述邻接矩阵视为输入,通过仅保持第一行和第一列的完整性来派生另一个矩阵 A0。将 k = 1 ,并将所有其他值替换为 A[i,k]+A[k,j]

A=\begin{matrix} 0 & 5& \infty & 6& \infty \\ \infty & & & & \\ 3& & & & \\ \infty& & & & \\ 2& & & & \\ \end{matrix}

A_{1}=\begin{matrix} 0 & 5& \infty & 6& \infty \\ \infty & 0& 1& \infty& 7\\ 3 & 8& 0& 4& \infty\\ \infty & \infty& 2& 0& 3\\ 2& 7& \infty& 5& 0\\ \end{matrix}

Step 3

将上述邻接矩阵视为输入,通过仅保持第一行和第一列的完整性来派生另一个矩阵 A0。将 k = 1 ,并将所有其他值替换为 A[i,k]+A[k,j]

A_{2}=\begin{matrix} & 5& & & \\ \infty & 0& 1& \infty& 7\\ & 8& & & \\ & \infty& & & \\ & 7& & & \\ \end{matrix}

A_{2}=\begin{matrix} 0 & 5& 6& 6& 12 \\ \infty & 0& 1& \infty& 7\\ 3 & 8& 0& 4& 15\\ \infty & \infty& 2& 0& 3\\ 2 & 7& 8& 5& 0 \\ \end{matrix}

Step 4

将上述邻接矩阵视为输入,通过仅保持第一行和第一列的完整性来派生另一个矩阵 A0 。将 k = 1 ,并将所有其他值替换为 A[i,k]+A[k,j]

A_{3}=\begin{matrix} & & 6& & \\ & & 1& & \\ 3 & 8& 0& 4& 15\\ & & 2& & \\ & & 8& & \\ \end{matrix}

A_{3}=\begin{matrix} 0 & 5& 6& 6& 12 \\ 4 & 0& 1& 5& 7\\ 3 & 8& 0& 4& 15\\ 5 & 10& 2& 0& 3\\ 2 & 7& 8& 5& 0 \\ \end{matrix}

Step 5

将上述邻接矩阵视为输入,通过仅保持第一行和第一列的完整性来派生另一个矩阵 A0 。将 k = 1 ,并将所有其他值替换为 A[i,k]+A[k,j]

A_{4}=\begin{matrix} & & & 6& \\ & & & 5& \\ & & & 4& \\ 5 & 10& 2& 0& 3\\ & & & 5& \\ \end{matrix}

A_{4}=\begin{matrix} 0 & 5& 6& 6& 9 \\ 4 & 0& 1& 5& 7\\ 3 & 8& 0& 4& 7\\ 5 & 10& 2& 0& 3\\ 2 & 7& 7& 5& 0 \\ \end{matrix}

Step 6

将上述邻接矩阵视为输入,通过仅保持第一行和第一列的完整性来派生另一个矩阵 A0 。将 k = 1 ,并将所有其他值替换为 A[i,k]+A[k,j]

A_{5}=\begin{matrix} & & & & 9 \\ & & & & 7\\ & & & & 7\\ & & & & 3\\ 2 & 7& 7& 5& 0 \\ \end{matrix}

A_{5}=\begin{matrix} 0 & 5& 6& 6& 9 \\ 4 & 0& 1& 5& 7\\ 3 & 8& 0& 4& 7\\ 5 & 10& 2& 0& 3\\ 2 & 7& 7& 5& 0 \\ \end{matrix}

Analysis

根据上述伪代码,Floyd-Warshall 算法使用三个 for 循环来找到图中所有顶点对之间的最短距离。因此,Floyd-Warshall 算法的 time complexityO(n3) ,其中“n”是图中顶点的数量。该算法的 space complexityO(n2)

Implementation

以下是用弗洛伊德·沃舍尔算法来查找带权邻接矩阵中图中最短路径的实现 -