Algorithms · Weighted graphs

All-pairs shortest paths: Johnson and Floyd–Warshall

When distances between every pair of vertices are needed, repeating a single-source search is one option. Floyd–Warshall builds the matrix directly; Johnson makes the weights nonnegative and runs Dijkstra from every source.

Prerequisites: Dijkstra, Bellman–Ford and relaxation.

1. The problem

Given a directed weighted graph G = (V, E), we want a matrix D where D[i][j] is the minimum cost from i to j. Its diagonal is 0 when no negative cycle exists; D[i][j] = +∞ when j is unreachable from i. If several edges connect i to j, initialization uses the lightest one.

A negative cycle changes the question. If i can reach the cycle and the cycle can reach j, the cost of a walk from i to j is unbounded below: write −∞. Another pair may still have a finite distance or be unreachable.

For one source, start with the preceding guide. For all pairs, graph structure matters: Floyd–Warshall visits every triple of vertices, whereas Johnson takes advantage of sparse edge sets.

2. One graph for both algorithms

Consider four vertices A, B, C, D and the following directed edges. B → C has a negative weight, but cycle B → C → D → B weighs −2 + 2 + 1 = 1: it is not negative.

Edges of the example graph
A → BA → CB → CB → DC → DD → B
38−2521

From A to D, for example, route A → B → C → D weighs 3 − 2 + 2 = 3; A → B → D weighs 8. There is no route from C to A.

3. Floyd–Warshall: allow more intermediates

Number the vertices. D(k)[i][j] is the minimum cost from i to j when only the first k vertices may appear as internal vertices. An optimal route either avoids k or passes through k; in the latter case it combines routes i → k and k → j.

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

Initialize the diagonal to 0, edges to their weights and all remaining cells to +∞. The loop over k must be outermost: each phase allows exactly one more possible intermediate. Cells may be updated in the same matrix when no negative cycle exists.

for each i, j: D[i][j] = 0 if i = j; otherwise +∞
for each edge i → j of weight w: D[i][j] = min(D[i][j], w)
for each vertex k:
    for each vertex i:
        for each vertex j:
            if D[i][k] and D[k][j] are finite:
                D[i][j] = min(D[i][j], D[i][k] + D[k][j])

In the example, allowing B as an intermediate reduces A → C from 8 to 3 + (−2) = 1. Then C reduces A → D from 8 to 1 + 2 = 3. Finally D gives C → B at cost 2 + 1 = 3.

Final distance matrix D
From / toABCD
A0313
B∞0−20
C∞302
D∞1−10

To reconstruct routes, also store next[i][j], the first vertex after i on the route to j. Initially next[i][j] = j for a direct edge; when going through k improves D[i][j], set next[i][j] = next[i][k].

4. Johnson: reweight and repeat Dijkstra

Johnson suits sparse graphs that may have negative edges but no negative cycles. Add an artificial vertex q and zero-weight edges q → v to every original vertex. Run Bellman–Ford from q: the resulting distance h(v) is a potential. If Bellman–Ford detects a negative cycle, stop.

w′(u,v)=w(u,v)+h(u)−h(v)≥0

The inequality follows from Bellman–Ford: h(v) ≤ h(u) + w(u,v). Reweighted edges are therefore suitable for Dijkstra. This adjustment preserves optimal routes: along any route from s to t, intermediate potentials cancel, so the new weight is the original weight plus h(s) − h(t).

δ(s,t)=δ′(s,t)−h(s)+h(t)
add q and zero-weight edges q → v
h = Bellman–Ford(G with q, source q)
if there is a negative cycle: stop
for every edge u → v: w′(u,v) = w(u,v) + h(u) − h(v)
for each original source s:
    δ′ = Dijkstra(G with weights w′, source s)
    for each reachable t: D[s][t] = δ′(s,t) − h(s) + h(t)
    for each unreachable t: D[s][t] = +∞

For the example graph, Bellman–Ford from q gives h(A) = 0, h(B) = 0, h(C) = −2, h(D) = 0. Reweighted edges A → B, A → C, B → C, B → D, C → D, D → B have weights 3, 10, 0, 5, 0, 1 respectively: none is negative.

Dijkstra from A finds δ′(A,C) = 3 via B; restoring the potential gives D[A][C] = 3 − 0 + (−2) = 1. From D it finds δ′(D,C) = 1 via B; the original cost is 1 − 0 + (−2) = −1. These match the Floyd–Warshall matrix.

5. Interactive lab

Edit the edges and compare both algorithms on the same graph. Step through Floyd–Warshall matrix checks, or follow Johnson’s potentials and each Dijkstra search. Choose a pair to see its reconstructed route; distances are provisional during the animation. The lab uses explicit scans for Dijkstra; the complexity table assumes a priority queue.

6. Negative cycles

Floyd–Warshall detects a negative cycle if, at the end, some D[k][k] < 0. For a pair (i, j), the value is −∞ if some such k has finite D[i][k] and D[k][j]: the route can reach the cycle and then j. Checking the diagonal alone does not identify every affected pair.

Johnson finds any negative cycle in the graph because q reaches every vertex. It then does not produce an ordinary finite-distance matrix. If unaffected pairs are needed, use the reachability check through negative cycles after Floyd–Warshall.

In the example, changing D → B from 1 to −1 makes B → C → D → B a cycle of weight −1. A → D becomes −∞; C → A remains +∞ because A cannot be reached from C.

7. Choice and complexity

MethodWhen to use itTimeMemory for the matrix
Floyd–WarshallSmall or dense graphs; simple implementation; analysis of pairs affected by negative cyclesO(|V|³)O(|V|²)
JohnsonSparse graphs, possibly with negative edges but no negative cyclesO(|V|(|V| + |E|) log |V|)O(|V|² + |E|)
Dijkstra from every vertexAll weights already nonnegativeO(|V|(|V| + |E|) log |V|)O(|V|² + |E|)

The Johnson and Dijkstra bounds assume a simple graph, adjacency lists and a binary heap; they include the output matrix. Johnson also runs an initial Bellman–Ford, whose cost is covered by the displayed bound. If rows are consumed one at a time, Johnson’s auxiliary memory drops to O(|V| + |E|). Floyd–Warshall uses O(|V|²) even with a next-vertex matrix.

Practical choice. When |E| is close to |V|, Johnson is usually a better fit than Floyd–Warshall’s triple loop. When |E| is close to |V|², Floyd–Warshall avoids many Dijkstra runs. For one source, use the appropriate single-source algorithm directly.

8. Mistakes and exercises

  • Reordering Floyd–Warshall loops: k must remain outermost because it identifies which intermedi are allowed in each phase.
  • Running Dijkstra on Johnson’s original negative weights: first reweight edges using the potentials.
  • Forgetting the final correction: distances with reweighted edges are not the original distances.
  • Confusing +∞ with a negative cycle: it means unreachable; −∞ means the cost is unbounded below.
1. What is D[B][D] in the example, and which route attains it?

It is 0: B → C → D weighs −2 + 2 = 0, versus 5 for the direct edge.

2. With h(B) = 0 and h(C) = −2, what is the reweighted B → C edge?

w′(B,C) = −2 + 0 − (−2) = 0. The potential removes the negative edge weight without changing the optimal route for a fixed pair.

3. After changing D → B to −1, what are the values for A → D and C → A?

A → D is −∞: A can reach the negative cycle and the cycle can reach D. C → A is +∞: no edge leads to A.

4. When can Bellman–Ford be skipped in favor of repeated Dijkstra?

When all original edge weights are nonnegative. No reweighting is needed; each source produces one matrix row.