Floyd-Warshall — all-pairs shortest paths, O(V³)
WHAT is the problem?
The output is a full matrix of distances (and optionally a matrix to reconstruct paths).
WHY a new algorithm (and not just run Dijkstra V times)?
- Running Dijkstra from every source: — but breaks with negative edges.
- Running Bellman-Ford from every source: , which for dense graphs () is .
- Floyd-Warshall: a clean , handles negative edges, and is 5 lines of code. For dense graphs and small (say ) it's the king.
HOW: derive it from scratch (dynamic programming)
Let's define a subproblem carefully — this is the heart of it.
Base case (): no intermediate vertices allowed, so the only legal paths are single edges.
Transition — the key insight. Consider the shortest path from to using intermediates . Vertex is either used by this path or not:
- is NOT used → the path only uses , so its length is .
- IS used → because there are no negative cycles, the optimal path visits exactly once. Split it at : a piece and a piece , each using only as intermediates. So its length is .
We take the better of the two:
Collapsing to a 2D array (the in-place trick)
The recurrence updates layer from layer . We can overwrite the same matrix . Is that safe? When computing using :
- in the new layer = . Since (no negative cycle), it's unchanged.
- Same for .
So overwriting does not corrupt the values we read. Hence one matrix suffices.
def floyd_warshall(n, dist): # dist[i][j] = weight or INF, dist[i][i]=0
for k in range(n): # k = intermediate vertex being "unlocked"
for i in range(n):
for j in range(n):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distDetecting negative cycles
After running, check the diagonal. If any , then lies on a negative cycle (you found a path from back to cheaper than staying put).
Path reconstruction
Keep a next[i][j] (or parent[i][j]) matrix. Initialize next[i][j] = j for each edge. Whenever you relax through , set next[i][j] = next[i][k]. To rebuild : follow next until you reach .

Worked Example 1 — a tiny 3-node graph
Vertices . Edges: , , . No others.
Initial matrix ( shown as ):
| from\to | 0 | 1 | 2 |
|---|---|---|---|
| 0 | 0 | 4 | 11 |
| 1 | · | 0 | 2 |
| 2 | · | · | 0 |
Unlock : any path improved by going through 0? Nothing points into 0, so no change. Why this step? for , so is huge.
Unlock : check vs . Update . Why this step? Now route is legal because 1 is unlocked.
Unlock : 2 has no outgoing edges, no improvements.
Final . ✔
Worked Example 2 — negative edge (where Dijkstra fails)
Vertices . Edges: , , .
Initial: .
: vs → update . Why this step? The negative edge makes the detour through 1 cheaper — Floyd-Warshall handles it naturally since min doesn't care about edge sign (as long as no negative cycle).
Final . Dijkstra would have wrongly committed to .
Worked Example 3 — negative cycle detection
Edges: . Cycle total .
After running, relaxes to . The diagonal goes negative → negative cycle detected. Why this step? The diagonal starts at 0; only a negative loop back to can push it below 0.
Recall Feynman: explain to a 12-year-old
Imagine cities connected by roads with travel times. You want the fastest time between every pair of cities. You play a game: "What if I'm now allowed to stop at City A on the way?" You recheck every pair: maybe going through A is faster. Then you unlock City B too, recheck everyone again. Then City C... After you've unlocked all cities, every pair already has its fastest time. That's it — you just kept asking "would stopping at this new city help?" for one city at a time.
Active Recall
What does the DP state represent in Floyd-Warshall?
What is the Floyd-Warshall recurrence?
What is the time and space complexity of Floyd-Warshall?
Why must the loop be outermost?
How do you detect a negative cycle with Floyd-Warshall?
Can Floyd-Warshall handle negative edge weights?
Why is the in-place single-matrix update correct?
What is the base case () matrix?
How do you reconstruct paths in Floyd-Warshall?
next[i][j]; init to for edges; on relaxation through set next[i][j]=next[i][k]; follow next to rebuild.When is Floyd-Warshall better than running Dijkstra V times?
Connections
- Dijkstra's Algorithm — single-source, non-negative weights only
- Bellman-Ford — single-source, handles negatives, detects negative cycles
- Dynamic Programming — Floyd-Warshall is layered DP over intermediate sets
- Johnson's Algorithm — APSP for sparse graphs, reweights then runs Dijkstra
- Transitive Closure — same loop structure with OR instead of min (Warshall's algorithm)
- Negative Cycles — detection via the diagonal
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Floyd-Warshall ka core idea bahut simple hai: tum har pair of cities ke beech ka shortest distance ek saath nikalna chahte ho. Tum ek game khelte ho — "Agar main beech mein City pe ruk sakta hoon, toh kya koi route sasta ho jata hai?" Tum ek-ek karke har city ko "unlock" karte ho, aur har baar saare pairs ko recheck karte ho: d[i][j] = min(d[i][j], d[i][k] + d[k][j]). Jab saari cities unlock ho jaati hain, har pair ke paas already best answer hota hai.
Sabse important baat: k ka loop hamesha sabse bahar (outermost) hona chahiye. Yeh isliye kyunki yeh ek dynamic programming hai jo pe recurse karti hai — pehle ek intermediate city ke liye saare pairs settle ho, tab agli city unlock karo. Agar tum k ko andar daal d-oge toh aadhe-adhure values padhoge aur galat answer aayega. Yaad rakhne ka trick: K-I-J, "Kings Inspect Journeys".
Floyd-Warshall ki khaasiyat yeh hai ki yeh negative edges ko handle kar leta hai (Dijkstra nahi kar sakta), bas negative cycle nahi hona chahiye. Aur negative cycle pakadna bhi easy hai — algorithm chalne ke baad agar koi hai, matlab us vertex se ghoom ke wapas aane ka cost negative hai, yani negative cycle hai. Complexity hai, code sirf 4-5 lines, isliye dense graphs aur chhote (jaise ) ke liye yeh perfect hai — competitive programming mein bahut kaam aata hai.