Floyd-Warshall computes the shortest distance between every ordered pair in a weighted directed graph, producing a full V×V table. Running a single-source algorithm from each vertex can produce the same table, but on a dense graph that repeats much of the work. Negative edge weights also rule out Dijkstra.

Floyd-Warshall fills the whole table with one triple loop by recasting the problem as dynamic programming over a growing set of permitted waypoints. The sub-problem is “the shortest path from i to j that may route only through intermediate vertices drawn from {0..k}.” Beginning with direct edges alone and admitting one more permitted intermediate per stage, the last stage leaves every entry at its unrestricted shortest distance when no negative cycle is reachable on the route. Each stage k poses a single question at every pair: keep dist[i][j], or improve it by going i → k → j. A negative cycle makes every pair that can reach it and then leave it have no finite shortest distance. The diagonal detects the condition, but the raw finite values left in the matrix are not valid answers for those pairs.

The decisive step is a single relaxation sweeping the whole distance matrix for one admitted intermediate vertex.

Visualization

The table starts with direct edges and for missing routes. At each stage k, the highlighted cell compares its current dist[i][j] with the route through k; green writes improve the matrix and gray cells keep the existing distance.

Let D^(k)[i][j] mean the best ij distance whose intermediate vertices are drawn from {0..k}; D^(-1) contains direct edges, zero-length self paths, and elsewhere. Each stage moves from D^(k-1) to D^(k) with:

D^(k)[i][j] = min(D^(k-1)[i][j], D^(k-1)[i][k] + D^(k-1)[k][j])

The invariant: once stage k finishes, D^(k)[i][j] is the shortest finite ij path using intermediate vertices only from {0..k}. Each pair has exactly two ways to satisfy stage k. Either the best path avoids k, and D^(k-1)[i][j] already holds it; or it passes through k exactly once, splitting into an ik leg and a kj leg that each use only earlier intermediates. Taking the smaller value extends the invariant while no negative cycle makes the optimum unbounded below.

That decomposition is why k is the outermost loop. It reads dist[i][k] and dist[k][j] as the previous stage left them, so the entire matrix has to finish updating for one k before the next begins. Running i or j outside k mixes cells from two different stages into one relaxation, and the recurrence consumes half-finished data.

During stage k neither dist[i][k] nor dist[k][j] can improve — a shortest path through k never uses k as an intermediate of its own legs — so reading and writing the same array yields the values a separate previous copy would have held.

A four-vertex run shows the layering. is shown as .:

Vertices 0..3, directed edges (weight):
  0→1 (3)  0→3 (7)  1→0 (8)  1→2 (2)  2→0 (5)  2→3 (1)  3→0 (2)
 
dist after init:            final all-pairs distances:
      0   1   2   3               0   1   2   3
  0 [ 0   3   .   7 ]         0 [ 0   3   5   6 ]
  1 [ 8   0   2   . ]         1 [ 5   0   2   3 ]
  2 [ 5   .   0   1 ]         2 [ 3   6   0   1 ]
  3 [ 2   .   .   0 ]         3 [ 2   5   7   0 ]

dist[0][3] holds the direct edge 7 until vertex 2 becomes admissible at stage k = 2, where 0→2→3 costs 5 + 1 = 6 and wins. dist[1][3] first drops to 15 through vertex 0 at k = 0, then to 3 at k = 2 via 1→2→3. No diagonal entry ends negative, so the graph carries no negative cycle.

Complexity
  • Every input: Θ(n³)
n
number of vertices

Diagram and C# Implementation

When the Reported Distances Are Wrong

A negative edge is fine on its own — a stage relaxes through it and the invariant still holds. A negative cycle is not: looping it lowers the total without bound, so every pair that can reach the cycle and then leave it has shortest distance −∞. The signal lives on the diagonal. When dist[w][w] < 0, there is a negative closed walk reachable from w and back to w. It is a witness, not proof that w itself lies on a simple negative cycle. Every dist[u][v] with finite dist[u][w] and dist[w][v] is affected and must be marked −∞ or excluded from results. The plain distance matrix detects this condition but does not extract the concrete cycle. Record predecessors during relaxation when the cycle itself matters.

Reordering the loops so i or j is outermost still compiles, runs, and terminates, but it relaxes pairs against cells from a stage that has not finished. The matrix comes back full of finite numbers that are simply wrong wherever a shortest path needed an intermediate whose row or column was consulted before that stage completed. Because nothing crashes, the defect hides until a specific graph exposes it.

Overflow is the other silent corruptor. With int.MaxValue as , the unconditional dist[i][k] + dist[k][j] wraps to a large negative number whenever both operands are the sentinel, and that phantom shortcut then propagates through the rest of the sweep. Representing an absent edge as null avoids a numeric sentinel, but finite path sums can still exceed long. The checked addition in the sample makes that input-contract violation explicit.

References