Lesson 19 of 39
Floyd-Warshall Algorithm for All-Pairs Shortest Paths
Master the Floyd-Warshall algorithm — understand the DP recurrence, implement it in Python, detect negative cycles, and know when to pick it over Dijkstra.
What you'll learn
- ✓The DP recurrence behind Floyd-Warshall
- ✓How to implement all-pairs shortest paths in Python
- ✓How to reconstruct the actual shortest path
- ✓Detecting negative-weight cycles
- ✓When to choose Floyd-Warshall over Dijkstra or Bellman-Ford
Prerequisites
- •Graph basics — adjacency matrix representation
- •Dynamic programming fundamentals
- •Familiarity with Dijkstra and Bellman-Ford helps
When you need the shortest path between every pair of vertices — not just from a single source — Floyd-Warshall is the textbook answer. It runs in O(V³) time, fits in a clean triple loop, and handles negative edge weights (as long as there are no negative cycles).
The Core Idea
Floyd-Warshall uses a simple DP insight: for every pair of vertices (i, j), check whether routing through an intermediate vertex k gives a shorter path than the current best.
Let dist[i][j] be the shortest distance from i to j. For each intermediate vertex k, update:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
By iterating k from 0 to V-1 as the outer loop, every possible intermediate vertex is considered.
Before considering k:
i -----(5)-----> j
After considering k:
i —(2)—> k —(1)—> j total = 3 < 5 ✓ update!
Implementation in Python
def floyd_warshall(n, edges):
INF = float('inf')
dist = [[INF] * n for _ in range(n)]
for i in range(n):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
for k in range(n):
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 dist
edges = [(0, 1, 3), (0, 2, 8), (1, 2, 2), (2, 0, 5), (2, 3, 1), (3, 1, 7)]
result = floyd_warshall(4, edges)
for row in result:
print([x if x != float('inf') else '∞' for x in row])
# [0, 3, 5, 6]
# ['∞', 0, 2, 3]
# [5, 7, 0, 1] (2→0 via direct edge weight 5)
# ['∞', 7, 9, 0]
Path Reconstruction
To recover the actual path, maintain a next_node matrix. next_node[i][j] stores the first vertex on the shortest path from i to j.
def floyd_warshall_with_path(n, edges):
INF = float('inf')
dist = [[INF] * n for _ in range(n)]
nxt = [[None] * n for _ in range(n)]
for i in range(n):
dist[i][i] = 0
nxt[i][i] = i
for u, v, w in edges:
dist[u][v] = w
nxt[u][v] = v
for k in range(n):
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]
nxt[i][j] = nxt[i][k]
return dist, nxt
def reconstruct_path(nxt, u, v):
if nxt[u][v] is None:
return []
path = [u]
while u != v:
u = nxt[u][v]
path.append(u)
return path
Detecting Negative Cycles
A negative cycle exists if any diagonal entry becomes negative after running the algorithm:
def has_negative_cycle(dist):
for i in range(len(dist)):
if dist[i][i] < 0:
return True
return False
If dist[i][i] < 0, vertex i lies on a negative cycle — you can keep going around and reducing the total weight indefinitely.
Complexity Analysis
| Aspect | Value |
|---|---|
| Time | O(V³) |
| Space | O(V²) for the distance matrix |
| Works with negative weights? | Yes |
| Detects negative cycles? | Yes |
For sparse graphs with a single source, Dijkstra (O(E log V)) or Bellman-Ford (O(VE)) is faster. Floyd-Warshall wins when you need all pairs and V is small to moderate (under ~500).
When to Use Floyd-Warshall
- All-pairs shortest paths — the classic use case.
- Transitive closure — is vertex
ireachable from vertexj? ReplaceminwithORand+withAND. - Dense graphs — adjacency matrix is natural; Dijkstra’s edge-list approach gains less here.
- Small V —
V³is fine whenV ≤ 400; beyond that, consider running Dijkstra from each source.
Interview Tips
- Mention that Floyd-Warshall is
O(V³)regardless of edge count — it always considers all pairs through all intermediates. - If the interviewer asks about negative weights, point out that Floyd-Warshall handles them but Dijkstra does not.
- For a single-source query, suggest Dijkstra first; only reach for Floyd-Warshall when asked about all pairs.
- The
kloop must be the outermost — getting the loop order wrong is a common bug. - Path reconstruction with the
nextmatrix is a frequent follow-up; practice writing it from memory.
Progress is saved locally to your browser.