3.5.12 · D4Graphs

Exercises — Floyd-Warshall — all-pairs shortest paths, O(V³)

2,778 words13 min readBack to topic

This page is a self-testing ladder. Each problem builds on the parent note. Read the problem, cover the solution, try it, then reveal. Difficulty climbs from L1 Recognition (do you know the rule?) to L5 Mastery (can you invent new uses?).


Level 1 — Recognition

L1.1 — State the state

Recall Solution

is the length of the ==shortest path from to that is allowed to use only the vertices as intermediate (middle) stops==. The endpoints and are always allowed; only the middle is restricted.

For no middle vertices are allowed, so the only legal path is a single direct edge (or staying put). The complete base case has three cases: In particular the diagonal starts at , which later becomes the key to the negative-cycle test.

L1.2 — Spot the loop bug

Recall Solution

No. The intermediate vertex ==k must be the outermost loop==. The dynamic program recurses on : every pair must fully account for the set before we unlock . With k innermost you read half-updated values and can return wrong distances.

L1.3 — Which algorithm?

Recall Solution

Floyd-Warshall. Dijkstra's Algorithm breaks on negative edges. Bellman-Ford run from every source costs for a dense graph. Floyd-Warshall gives clean and handles negative edges, provided there are no negative cycles (if a negative cycle exists, "shortest" is undefined — you could loop forever toward — and the algorithm instead detects it via the diagonal). For that is operations — instant.


Level 2 — Application

L2.1 — Hand-simulate a 3-node sweep

Recall Solution

Initial matrix ():

from\to 0 1 2
0 0 3 10
1 · 0 4
2 · · 0
  • (unlock vertex 0): nothing points into , so for . No detour through helps.
  • (unlock vertex 1): check vs . Update .
  • (unlock vertex 2): has no outgoing edge, no improvement.

Final . In the figure, the two-hop route (drawn in amber, weights then , total ) beats the single direct edge (drawn in white, weight ) — so the detour wins.

Figure — Floyd-Warshall — all-pairs shortest paths, O(V³)

L2.2 — Negative edge, no cycle

Recall Solution
  • (unlock vertex 1): vs . Update .

Final . The min operation does not care about the edge sign — it just compares numbers — so a negative edge is handled with zero extra code, unlike Dijkstra's Algorithm which would wrongly commit to .

L2.3 — Read the whole final matrix

Recall Solution

Initial:

0 1 2
0 0 1 100
1 · 0 2
2 7 · 0
  • (unlock vertex 0): vs → update . stays .
  • (unlock vertex 1): vs → update . vs (no, smaller).
  • (unlock vertex 2): now vertex may be a middle stop. The only pair that improves is : check update . Every other pair is checked but does not improve, because its current value is already the "through " candidate: vs (keep ); vs (keep ); vs (keep ). All diagonal entries stay , confirming no negative cycle.

Final:

0 1 2
0 0 1 3
1 9 0 2
2 7 8 0

Level 3 — Analysis

L3.1 — Detect a negative cycle

Recall Solution

Cycle total , so a negative cycle exists.

The proof appears on the diagonal. After the sweep, a path becomes legal and its length is : Because starts at , only a negative loop back to can push it below . Negative cycle detected (). In the figure, the three edges form a loop with total weight ; after the sweep the self-distance cell (highlighted in amber) reads instead of its starting .

Figure — Floyd-Warshall — all-pairs shortest paths, O(V³)

L3.2 — Why split at with both halves in ?

Recall Solution

If the optimal path passes through , we cut it at into and . Suppose the first piece revisited . Then it would contain a cycle from back to . With no negative cycles, any cycle has length , so removing it cannot make the path longer — the optimal choice never includes it. Hence the first half uses only as its endpoint, and its intermediate vertices lie in . That is precisely the previous subproblem , so the recursion closes on itself. This is the Dynamic Programming "optimal substructure" property.

L3.3 — In-place safety

Recall Solution

The entries we read, and , are exactly the ones that touch vertex as an endpoint. In iteration they could only change to But (no negative cycle), so unchanged. Same for . The values we read are stable throughout the -pass, so a single matrix is correct.


Level 4 — Synthesis

L4.1 — Reconstruct the actual path

Recall Solution

Initialise next:

  • diagonal: next[0][0]=0, next[1][1]=1, next[2][2]=2;
  • edges: next[0][1]=1, next[1][2]=2, next[0][2]=2, next[2][0]=0;
  • non-edges (unreachable so far): next[1][0]=None, next[2][1]=None.

This None marks "no known route yet" — if a pair stays None after the algorithm, no path exists, so reconstruction returns "unreachable".

When relaxes (via ), set next[2][1]=next[2][0]=0. When relaxes (via ), set next[0][2]=next[0][1]=1.

Rebuild : start at . next[0][2]=1 → go to . next[1][2]=2 → go to . Reached destination. Path , total weight . ✔

L4.2 — Transitive closure via the same loop

Recall Solution

Replace min(+) with OR(AND):

reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])

Meaning: reaches if it already did, or if reaches and reaches . This is Warshall's algorithm — same skeleton.

Apply: reach[0][1]=T, reach[1][2]=T. Under : reach[0][2] = F or (reach[0][1] and reach[1][2]) = T and T = True. So yes, reaches .

L4.3 — Johnson's connection

Recall Solution

Johnson's Algorithm. It uses Bellman-Ford once to compute a potential , reweights each edge , then runs Dijkstra's Algorithm from every vertex on the non-negative graph. Complexity — far better than when (sparse). For sparse negative-edge graphs, Johnson wins; for dense small graphs, Floyd-Warshall wins.


Level 5 — Mastery

L5.1 — Prove the operation count

Recall Solution

The three loops each run over all vertices, independently, so the inner line runs times. For : . This is why the complexity is exactly — no early exits, every triple is visited once.

L5.2 — Widest / bottleneck path (max-min semiring)

Recall Solution

Swap the operations: outer combine over the two path choices becomes max, and the "join two halves" becomes min (a path is only as wide as its narrowest edge):

w[i][j] = max( w[i][j], min(w[i][k], w[k][j]) )

This is Floyd-Warshall over the (max, min) semiring — the skeleton is identical.

Apply: direct gives bottleneck . Via : . Take . Widest bottleneck (route , narrowest edge ).

L5.3 — Design: transitive closure of a huge sparse graph

Recall Solution
  • Warshall: .
  • BFS from every source: .

BFS-from-every-source is faster by a factor of . Lesson: the triple loop is only "the king" for dense graphs and small ; on sparse graphs the per-source BFS/Dijkstra family wins by orders of magnitude.


Recall Final self-check
  1. Why is k outermost? ::: The DP recurses on ; each pair must finish accounting for before unlocking .
  2. What proves a negative cycle? ::: Some after the sweep.
  3. Why is the in-place single matrix safe? ::: keeps and unchanged during pass .
  4. When should you NOT use Floyd-Warshall? ::: Sparse graphs — prefer Johnson's Algorithm or per-source BFS/Dijkstra.