Floyd Warshall All Pairs Shortest Path in DSA Python - Time & Space Complexity
We want to understand how the time needed to find shortest paths between all pairs of points grows as the number of points increases.
How does the running time change when we add more points to the map?
Analyze the time complexity of the following code snippet.
INF = float('inf')
def floyd_warshall(graph):
n = len(graph)
dist = [row[:] for row in graph]
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
This code finds the shortest distance between every pair of points in a graph using three nested loops.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The triple nested loops that check and update distances between all pairs through an intermediate point.
- How many times: Each loop runs from 0 to n-1, so the innermost operation runs approximately n x n x n = n³ times.
As the number of points (n) increases, the number of operations grows very quickly because we check every pair of points for every possible intermediate point.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 1,000 |
| 100 | 1,000,000 |
| 1000 | 1,000,000,000 |
Pattern observation: When n doubles, the operations increase by about eight times (since n³ grows fast).
Time Complexity: O(n³)
This means the time needed grows roughly with the cube of the number of points, so adding more points makes the process much slower.
[X] Wrong: "Since there are three loops, the time complexity is O(n) because loops run one after another."
[OK] Correct: The loops are nested inside each other, so the total operations multiply, not add, leading to O(n³), not O(n).
Understanding this algorithm's time complexity helps you explain why some solutions are slower and shows your grasp of nested loops and their impact on performance.
"What if we replaced the triple nested loops with a recursive approach that splits the graph? How might the time complexity change?"
Practice
Floyd Warshall algorithm in graph theory?Solution
Step 1: Understand Floyd Warshall's goal
The Floyd Warshall algorithm calculates shortest paths between every pair of vertices in a weighted graph.Step 2: Compare with other graph algorithms
Minimum spanning tree, DFS, and cycle detection serve different purposes than Floyd Warshall.Final Answer:
To find the shortest paths between all pairs of vertices in a weighted graph -> Option AQuick Check:
Floyd Warshall = all pairs shortest paths [OK]
- Confusing with minimum spanning tree algorithms
- Thinking it finds shortest path from one source only
- Mixing with traversal algorithms like DFS or BFS
dist for Floyd Warshall in Python for a graph with n vertices?Solution
Step 1: Understand matrix initialization
We need a 2D list with size n x n, each element set to infinity initially.Step 2: Check each option
dist = [[float('inf')] * n for _ in range(n)] correctly creates a new list for each row with float('inf'). dist = [float('inf')] * n * n creates a 1D list, not 2D. dist = [[0] * n] * n creates shallow copies causing aliasing. dist = [0 for _ in range(n)] creates 1D list.Final Answer:
dist = [[float('inf')] * n for _ in range(n)] -> Option BQuick Check:
2D list with inf values = dist = [[float('inf')] * n for _ in range(n)] [OK]
- Using multiplication for 2D lists causing shared references
- Creating 1D list instead of 2D
- Initializing with zeros instead of infinity
graph = [
[0, 3, float('inf'), 7],
[8, 0, 2, float('inf')],
[5, float('inf'), 0, 1],
[2, float('inf'), float('inf'), 0]
]Solution
Step 1: Initialize dist matrix same as graph
Start with dist = graph matrix, where float('inf') means no direct edge.Step 2: Update distances using Floyd Warshall logic
Iterate k from 0 to 3, update dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]) for all i,j. After all iterations, shortest paths are computed.Final Answer:
[[0, 3, 5, 6], [5, 0, 2, 3], [3, 6, 0, 1], [2, 5, 7, 0]] -> Option AQuick Check:
All pairs shortest paths matrix = [[0, 3, 5, 6], [5, 0, 2, 3], [3, 6, 0, 1], [2, 5, 7, 0]] [OK]
- Not updating distances through intermediate vertices
- Confusing indices in nested loops
- Leaving float('inf') where shorter paths exist
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]What is the main bug if
dist[i][k] or dist[k][j] is float('inf')?Solution
Step 1: Understand addition with infinity in Python
float('inf') + any finite number = float('inf'), and float('inf') + float('inf') = float('inf').Step 2: Check the condition
The conditionif dist[i][k] + dist[k][j] < dist[i][j]will be False whenever the sum is inf, because inf is not less than any finite or inf value. Thus, no incorrect updates occur; invalid paths are correctly skipped.Final Answer:
No bug, the code works fine with infinity values -> Option CQuick Check:
inf + x = inf, inf < y always False for path updates [OK]
- Believing inf causes incorrect updates
- Confusing with integer overflow issues
- Thinking syntax error with inf
Solution
Step 1: Understand Floyd Warshall with negative edges
The algorithm can handle negative edges by updating distances through intermediate vertices, as long as no negative cycles exist.Step 2: Confirm no negative cycle condition
If negative cycles exist, shortest paths are undefined. Without them, Floyd Warshall converges to correct shortest paths.Final Answer:
It updates distances by considering intermediate vertices, correctly handling negative edges without cycles -> Option DQuick Check:
Negative edges allowed if no negative cycles [OK]
- Thinking Floyd Warshall cannot handle any negative edges
- Confusing negative edges with negative cycles
- Assuming preprocessing is always needed
Ready to prove it?
Pass the test and this pattern moves unknown
