Worked examples — Floyd-Warshall — all-pairs shortest paths, O(V³)
Two symbols we will use constantly, defined now so nothing is assumed:
The scenario matrix
Every graph you feed Floyd-Warshall lands in one or more of these boxes. Below the table, each row gets its own fully worked example.
| # | Case class | What makes it tricky | Example |
|---|---|---|---|
| A | All-positive edges | The "easy" baseline; a detour beats a direct edge | Ex 1 |
| B | A helpful negative edge | Detour becomes cheaper than the direct edge (Dijkstra breaks here) | Ex 2 |
| C | Unreachable pair | stays forever; must not relax through it | Ex 3 |
| D | Chained improvement | Unlocking a later builds on a previous 's work — proves loop order | Ex 4 |
| E | Negative cycle | "Shortest" is undefined; diagonal goes negative | Ex 5 |
| F | Tie / degenerate (self-loop, zero weight, equal routes) | min picks one; self-loop must not corrupt |
Ex 6 |
| G | Real-world word problem | Translate "cheapest flight" into a matrix | Ex 7 |
| H | Exam twist: wrong loop order | Same graph, broken code — see the actual wrong number | Ex 8 |
We will use small graphs so you can check every number by hand.
Case A — all-positive edges (baseline)

- Base matrix. , diagonal , everything else . Why this step? Floyd-Warshall must start from the direct-edge picture (, no midpoints allowed).
- Unlock . Nothing points into , so for and no relaxation fires. Why this step? is , never smaller.
- Unlock . Check vs . Relax: . Why this step? Now vertex is a legal midpoint, so route is finally on the table.
- Unlock . has no outgoing edges, so no path can pass through it. No change.
Verify: the only two routes are direct () and via (). . ✔
Case B — a helpful negative edge
- Base: .
- Unlock . vs . Relax: .
Why this step?
mindoes not care about the sign of an edge — it just adds and compares. A negative edge simply makes some sums smaller, which is exactly what a shortest-path algorithm wants. - Other unlocks change nothing.
Verify: routes : direct , via : . . ✔
Case C — an unreachable pair
- Base: (no edge), and has no outgoing edge at all.
- Through every unlock : to relax we would need to be finite. But for every (nothing leaves ). So the sum stays . Why this step? This is the guardrail. If you use a huge finite sentinel instead of true , be careful: can overflow or look "cheaper" than another HUGE. Use a value like and either skip relaxation when either term is the sentinel, or keep the sentinel far below overflow.
Verify: has out-degree , so is unreachable stays . ✔
Case D — chained improvement (why later builds on earlier )

- Base: , .
- Unlock . . Now costs using midpoint . Why this step? This half-built value () is exactly what the next unlock will reuse.
- Unlock . . Why this step? Here is the payoff: because step 2 already made , unlocking now reaches all the way to . A later stood on the shoulders of an earlier . This is precisely why must be the outer loop — the parent note's rule made concrete.
Verify: shortest is the 3-edge chain , beating direct . . ✔ This is Dynamic Programming in action: the answer for is assembled from the answer for .
Case E — a negative cycle

- Base: diagonal all ; .
- Unlock . .
- Unlock . . Why this step? The diagonal entry starts at ("stand still, cost nothing"). The only way it drops below is a genuine cheaper-than-standing-still loop back to — i.e. a negative cycle.
- Test: scan the diagonal. negative cycle reported.
Verify: cycle weight , and it pushes to . ✔ When this happens, all shortest-path outputs on that cycle are meaningless (you can loop to ). If you must handle negative cycles cleanly across a graph, that's where Johnson's Algorithm and reweighting come in.
Case F — degenerate: self-loop, zero weight, and a tie
- Base: — careful! We initialize the diagonal to (standing still is free), which is , so we keep , not the self-loop weight . Why this step? The DP defines . A positive self-loop can never beat standing still, so we ignore it. (A negative self-loop, however, would be a length-1 negative cycle — caught by Case E's test.)
- Unlock . Check vs . Tie with current ;
minkeeps . No harm. Why this step? This is the exact spot the parent note called "the in-place trick": we read and while overwriting the same matrix. Because , the values we read don't shift mid-iteration. The self-loop being effectively is what makes overwriting safe. - Tie handling. If two routes give equal distance,
<(strict) leaves the first one in place — the answer's value is unaffected; only the reconstructed path may differ.
Verify: and (self-loop of correctly unused). ✔
Case G — real-world word problem
-
Base matrix (rows/cols ):
from\to A B C D A 0 100 250 400 B · 0 100 -50 C · · 0 100 D · · · 0 -
Unlock (=1). . Also . Why this step? The rebate leg is a negative edge — Floyd-Warshall uses it without complaint, unlike a naïve greedy pricer.
-
Unlock (=2). vs ; not better than . No change.
-
Result: cheapest A\to D = \50A\to B\to D$.
Verify: routes : direct ; ; ; . Cheapest . ✔ (Units: all dollars, consistent.)
Case H — exam twist: the wrong loop order
- What the bug does. With innermost, for a fixed it sweeps all — but it does this before the pairs it depends on have been fully computed for outer . Concretely, when it processes , the entry has not yet been improved to (that improvement lives at pair , which for this ordering may come after or without the needed chain). Why this step? The DP recurrence requires that all pairs already account for midpoint set before you unlock . Only -outermost enforces that global barrier.
- Trace (k innermost). Processing : it tries for . At that moment is still (never relaxed yet, since pair hasn't been improved), so . And . So stays .
- Buggy output: , the direct edge — wrong (correct is ).
Verify: correct order gives ; the -innermost order on this graph gives . They differ, confirming the bug is real. ✔
Recall
Recall Which case is which?
Match each symptom to its case letter. A negative diagonal entry after the run ::: Case E — negative cycle. An entry stubbornly stuck at ::: Case C — unreachable pair. Detour cheaper than the direct edge because of a negative leg ::: Case B (or G) — helpful negative edge. Answer only appears after a second unlock builds on the first ::: Case D — chained improvement, proves -outermost. Wrong answer that equals the raw direct edge ::: Case H — not outermost. A positive self-loop that must be ignored ::: Case F — degenerate; diagonal stays .