Floyd-Warshall
Imagine you run an airline and want to know the cheapest fare between every pair of cities. You could run Dijkstra from each city, but here's a more elegant approach: ask, city by city, "Does flying via city K make any trip cheaper?"
Start with direct flight prices. Then ask: "Does routing through city 1 make any trip cheaper?" Update prices. Then: "Does routing through city 2 make any trip cheaper?" Update again. After you've considered every city as a potential layover, every entry in your price table is the true cheapest fare.
That's Floyd-Warshall — an all-pairs shortest path algorithm built on a beautifully simple DP idea.
The DP Formulation
Define dist[i][j] as the shortest path from i to j. Initially:
dist[i][j] = weight(i,j)if a direct edge existsdist[i][i] = 0dist[i][j] = ∞otherwise
The key recurrence — run for each intermediate vertex k from 1 to V:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
In plain English: "Is going from i to j via k cheaper than any route we've found so far?" After the outer loop completes all V values of k, every pair (i, j) holds the globally optimal answer.
Why In-Place Updates Are Safe
The 3D formulation dp[k][i][j] reduces to a 2D array. Why can you update in-place? When processing intermediate vertex k, the values dist[i][k] and dist[k][j] don't change during the k-th iteration — they represent paths using intermediates {1..k−1}, which are already optimal and don't route through k as an intermediate (routing through k to get to k would only add cost). So updating dist[i][j] in place using these values is always correct.
Detecting Negative Cycles
After running Floyd-Warshall, check the diagonal. If dist[i][i] < 0 for any vertex i, there's a negative cycle passing through i. The trivial path from i to i costs 0; if it went negative, the algorithm found a cycle with negative total weight. Any shortest path that routes through a negative cycle is undefined (infinitely cheap).
Transitive Closure
Replace min/+ with OR/AND (using boolean values) to compute whether each pair (i, j) is connected at all. This transitive closure variant runs in \(O(V^3)\) and answers reachability queries for all pairs in one sweep.
When to Use Floyd-Warshall vs. Dijkstra
For all-pairs shortest paths on a dense graph (E ≈ \(V^2\)) or when negative weights exist (use Bellman-Ford for single-source), Floyd-Warshall's \(O(V^3)\) often wins. On a sparse graph with only positive weights, running Dijkstra from every source costs \(O(V · (V+E)\) log V), which can be much better. The crossover is roughly when E ≪ \(V^2\).