A Bit of History
Donald B. Johnson published "Efficient Algorithms for Shortest Paths in Sparse Networks" in 1977, solving a specific gap left open by earlier deep dives in this series: Floyd-Warshall handles negative edges but runs in \(O(V^3)\) regardless of how sparse the graph is, while Dijkstra's algorithm is much faster on sparse graphs but breaks entirely in the presence of negative edge weights. Johnson's algorithm was previewed briefly in Part 10 and finally gets its own full treatment here, completing this series' all-pairs shortest path story.
Working Principle: Reweighting
The core idea is to transform the graph's edge weights so that they all become non-negative — allowing Dijkstra to be run safely from every vertex — without changing which paths are shortest. The algorithm proceeds in three stages:
- Add an auxiliary vertex \(q\) connected to every other vertex with a zero-weight edge, and run Bellman-Ford (from an earlier deep dive) from \(q\) to compute \(h(v)\), the shortest distance from \(q\) to every vertex \(v\) (this also detects any negative cycle, in which case the algorithm reports failure and stops).
- Reweight every edge \((u,v)\) with original weight \(w(u,v)\) to a new weight \(w'(u,v) = w(u,v) + h(u) - h(v)\) — guaranteed to be non-negative for every edge (a consequence of the triangle-inequality-like property Bellman-Ford's shortest distances satisfy).
- Run Dijkstra from every vertex using these new non-negative weights \(w'\), then convert each computed shortest-path distance back to the original weighting via \(d(u,v) = d'(u,v) - h(u) + h(v)\).
Key Insight
The reweighting formula \(w'(u,v) = w(u,v) + h(u) - h(v)\) is carefully constructed so that for any path from \(u\) to \(v\), the total added correction telescopes down to just \(h(u) - h(v)\) regardless of the path's length or which intermediate vertices it passes through — meaning the relative ordering of path lengths (which path is shortest) is completely unchanged, even though every individual edge weight has been shifted.
Worked Example
Consider a graph with one negative edge, say weight \(-2\) from \(B\) to \(C\), among otherwise positive edges. Bellman-Ford from the auxiliary vertex \(q\) computes \(h\)-values for every vertex; reweighting every edge using the formula above transforms the \(-2\) edge into a non-negative value (while every other edge's weight also shifts, but stays non-negative too) — the graph is now safe for Dijkstra. Running Dijkstra once from each vertex on this reweighted graph, then converting each result back with the inverse formula, produces the exact same all-pairs shortest distances Floyd-Warshall would have computed directly, but considerably faster on a sparse graph.
Why Reweighting Preserves Shortest Paths
For any path \(P = v_0 \to v_1 \to \cdots \to v_k\), the reweighted total cost is:
$$w'(P) = \sum_{i=1}^{k} w'(v_{i-1}, v_i) = \sum_{i=1}^{k} \big[w(v_{i-1}, v_i) + h(v_{i-1}) - h(v_i)\big] = w(P) + h(v_0) - h(v_k)$$
since every intermediate \(h(v_i)\) term appears once with a \(+\) sign and once with a \(-\) sign, canceling out (a telescoping sum). Since \(h(v_0) - h(v_k)\) is the same fixed constant for every path from \(v_0\) to \(v_k\) regardless of which intermediate vertices it uses, the path with minimum \(w(P)\) is guaranteed to also have minimum \(w'(P)\) — reweighting never changes which path is shortest, only shifts every path's cost by the same fixed amount.
Complexity Analysis
Bellman-Ford runs once in \(O(VE)\); Dijkstra (with a binary or Fibonacci heap) runs once per vertex, \(V\) times, at \(O(E \log V)\) each:
$$\text{Time: } O(VE + V^2 \log V) \qquad \text{vs. Floyd-Warshall's } O(V^3)$$
For sparse graphs (where \(E \ll V^2\), common in road networks and many real-world graphs), Johnson's algorithm is dramatically faster than Floyd-Warshall's dense-graph-oriented \(O(V^3)\) — precisely the "efficient algorithms for sparse networks" promised in the title of Johnson's original 1977 paper.
Implementation
Real-World Applications
Currency Arbitrage Detection
Currency exchange rates can be modeled as a graph where edge weights are the negative logarithm of the exchange rate — a profitable arbitrage cycle (converting currency A to B to C back to A for a net gain) corresponds precisely to a negative-weight cycle in this graph. Financial systems scanning for arbitrage opportunities across many currency pairs (a genuinely sparse graph, since most currency pairs aren't directly traded) benefit directly from Johnson's algorithm's sparse-graph efficiency, using its embedded Bellman-Ford negative-cycle detection step as the actual arbitrage-finding mechanism.
Exercises
- Verify the telescoping-sum argument by hand: pick a 3-edge path and confirm that the reweighted total cost equals the original cost plus \(h(v_0) - h(v_k)\).
- Explain why Johnson's algorithm needs to detect negative cycles during its Bellman-Ford step, and what "no well-defined shortest path" would mean if one existed.
- Compare Johnson's algorithm's complexity to Floyd-Warshall's on a graph with \(V=1000\) vertices and \(E=2000\) edges (a genuinely sparse graph) — which is asymptotically faster here, and by roughly how much?
- Challenge: Modify the implementation to also reconstruct and print the actual shortest path (not just its distance) between a specific pair of vertices.
Limitations
No Advantage on Dense Graphs
Johnson's algorithm's advantage over Floyd-Warshall shrinks and eventually disappears as a graph becomes dense (as \(E\) approaches \(V^2\)) — at that point, \(O(VE + V^2\log V)\) approaches or exceeds \(O(V^3)\), and Floyd-Warshall's simpler, more cache-friendly triple-nested-loop implementation may be preferable in practice despite matching or worse asymptotic complexity.