Yasir Explains/Algorithms/Single-Source Shortest Path Algorithms/Floyd's Algorithm: All-Pairs Shortest Paths
Single-Source Shortest Path Algorithms

Floyd's Algorithm: All-Pairs Shortest Paths

On this page

From 'can I get there?' to 'how cheaply?'The recurrence — allow one more stopover at a timeStep-by-step visualizationPseudocodeComplexity analysis
Single-Source Shortest Path Algorithms

Floyd's Algorithm: All-Pairs Shortest Paths

Shortest distances between every pair of vertices in one Θ(V³) sweep — swap Warshall's OR/AND for min/+ and the same three loops compute distances instead of reachability. Handles negative edges, and the diagonal exposes negative cycles.

From 'can I get there?' to 'how cheaply?'

Warshall's algorithm answers reachability for every pair. Floyd's algorithm (often Floyd–Warshall) upgrades the same three-loop skeleton to compute shortest distances for every pair:

D[i][j] = the minimum total weight of any path from i to j.

The transformation is one substitution. Where Warshall combines facts with OR / AND:

Example
R[i][j] = R[i][j] OR (R[i][k] AND R[k][j])

Floyd combines costs with min / +:

Example
D[i][j] = min( D[i][j], D[i][k] + D[k][j] )

Read it aloud: "the best way from i to j is either what I already know, or going via k — whichever is cheaper."

When do you want all pairs at once? Route-planning tables, computing a graph's diameter, finding the cheapest cycle, or as a preprocessing step when many distance queries follow. And because it never settles anything (unlike Dijkstra), negative edges are fine — only negative cycles are off-limits, and Floyd even detects those.

The recurrence — allow one more stopover at a time

Exactly like Warshall, define D⁽ᵏ⁾[i][j] = the length of the shortest i → j path whose intermediate vertices all come from {1, …, k}:

  • D⁽⁰⁾ = the weight matrix: w(i→j) where an edge exists, 0 on the diagonal, ∞ elsewhere.
  • Going from k−1 to k: the best path allowed to use k either skips k (cost D⁽ᵏ⁻¹⁾[i][j]) or passes through it exactly once (cost D⁽ᵏ⁻¹⁾[i][k] + D⁽ᵏ⁻¹⁾[k][j]). Take the minimum.
  • D⁽ⁿ⁾ = true shortest distances.
Example
D⁽ᵏ⁾[i][j] = min( D⁽ᵏ⁻¹⁾[i][j], D⁽ᵏ⁻¹⁾[i][k] + D⁽ᵏ⁻¹⁾[k][j] )

This is dynamic programming on the set of allowed intermediates — the subproblem index is k, not a vertex or a path.

Negative cycle detection: the diagonal starts at D[i][i] = 0. If any D[i][i] ever drops below zero, vertex i lies on a cycle whose total weight is negative — at that point "shortest path" stops being well-defined for pairs that can detour through that cycle.

Step-by-step visualization

Run Floyd on a 4-vertex weighted digraph (edges 1→3 (3), 2→1 (2), 3→2 (7), 3→4 (1), 4→1 (6)). Step forward and backward with the ← / → arrow keys or the buttons below.

What to watch:

  • For each intermediate k (cyan row/column), every pair (i, j) is asked: is the detour i → k → j cheaper? The two cyan cells are the detour halves D[i][k] and D[k][j]; the amber-ringed cell is the target D[i][j]. Improvements flash green.
  • Early ∞ entries melt away as detours appear: D[2][3] becomes 2 + 3 = 5 the moment k = 1 lets paths hop through vertex 1.
  • At k = 3 the matrix fills in fastest — vertex 3 is the graph's main junction (1→3 and 3→ everything).
  • The very last improvement (k = 4) shortens D[3][1] from 9 to 7 via 3 → 4 → 1 — even an already-finite entry can keep improving until the final round.
327161234

The digraph — cyan = intermediate vertex k, amber = the pair (i, j) being checked.

Distance matrix D

1
2
3
4
1
0
∞
3
∞
2
2
0
∞
∞
3
∞
7
0
1
4
6
∞
∞
0
Detour cells D[i][k], D[k][j]Target cell D[i][j]Just improved
Start: D⁽⁰⁾ holds the direct edge weights — D[i][j] = w(i→j), 0 on the diagonal, ∞ where no edge exists.
1 / 27
Speed

Tip: step through with the ← / → arrow keys.

Pseudocode

Identical shape to Warshall — three loops, k outermost — with min/+ in the middle and an ∞-guard so that nonexistent paths don't poison the arithmetic. Path reconstruction needs one extra matrix next[i][j] (the first hop on the best known i → j path), updated whenever a detour wins. The C++ tab runs the visualization's graph and prints the final distance matrix.

1FLOYD(weight matrix W[1..n][1..n]):
2 // W[i][j] = edge weight, 0 on the diagonal, ∞ if no edge
3 D = W // D(0): direct edges only
4
5 for k = 1 to n: // allow vertex k as a stopover
6 for i = 1 to n:
7 for j = 1 to n:
8 if D[i][k] + D[k][j] < D[i][j]: // detour via k is cheaper
9 D[i][j] = D[i][k] + D[k][j]
10 next[i][j] = next[i][k] // (optional) path tracking
11
12 // Negative-cycle check:
13 for i = 1 to n:
14 if D[i][i] < 0: report "negative cycle through i"
15
16 return D
17
18// Reconstruct the path i -> j using next[][]
19// (next[i][j] = first hop of the best i -> j path; init next[i][j] = j for edges):
20PATH(i, j):
21 if D[i][j] == ∞: return "unreachable"
22 P = [i]
23 while i != j:
24 i = next[i][j]
25 append i to P
26 return P

Complexity analysis

The same accounting as Warshall:

  • Time: Θ(V³) — three loops, constant work inside, no dependence on E.
  • Space: Θ(V²) for the distance matrix (plus another V² for next if you need actual paths). The in-place update is safe: during round k, the cells D[i][k] and D[k][j] cannot themselves improve in that round (a detour through k doesn't shorten a path to k — that would require a negative D[k][k], i.e. a negative cycle).

How it compares for all-pairs distances:

ApproachTimeNegative edges
FloydΘ(V³)✓ (no negative cycles)
Dijkstra × VO(V·(V + E) log V)✗
Bellman–Ford × VO(V²·E)✓

For dense graphs (E ≈ V²) Floyd matches Dijkstra-from-every-vertex while being dramatically simpler — about five lines of code with no data structures. For large sparse graphs with non-negative weights, repeated Dijkstra wins.

Complexity Analysis

Time Complexity

Θ(V³) — independent of the number of edges.

Space Complexity

Θ(V²) for the distance matrix, updated in place; another Θ(V²) if you also track next[][] for path reconstruction.

Negative edges are fine; negative cycles are not (detected by a negative diagonal entry). For large sparse graphs with non-negative weights, running Dijkstra from every vertex is asymptotically faster.

Growth Rate Comparison

n (input size)O(1)O(log n)O(n)O(n log n)O(n²)