Floyd Warshall All Pairs Shortest Path in DSA Rust - 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 work change when we add more points to the map?
Analyze the time complexity of the following code snippet.
fn floyd_warshall(graph: &mut Vec<Vec<i32>>) {
let n = graph.len();
for k in 0..n {
for i in 0..n {
for j in 0..n {
if graph[i][k] != i32::MAX && graph[k][j] != i32::MAX && graph[i][k] + graph[k][j] < graph[i][j] {
graph[i][j] = graph[i][k] + graph[k][j];
}
}
}
}
}
This code updates the shortest distances between every pair of points by checking if going through an intermediate point is shorter.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The triple nested loops that check and update distances between all pairs through each intermediate point.
- How many times: Each loop runs from 0 to n-1, so the innermost operation runs about n x n x n = n³ times.
As the number of points (n) grows, the number of checks grows much faster because we check every pair through every intermediate point.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 1,000 |
| 100 | 1,000,000 |
| 1000 | 1,000,000,000 |
Pattern observation: The work grows by the cube of n, so doubling n makes the work about eight times bigger.
Time Complexity: O(n³)
This means the time needed grows very quickly as the number of points increases, because we check all pairs through all intermediate points.
[X] Wrong: "Since we only have three loops, the time complexity should be O(n)."
[OK] Correct: Each loop runs n times, so the total work multiplies, making it n x n x n = n³, not just n.
Understanding this cubic growth helps you explain why Floyd Warshall is good for small graphs but not for very large ones, showing your grasp of algorithm efficiency.
"What if we used a graph with fewer edges and skipped some checks? How would the time complexity change?"
Practice
Solution
Step 1: Understand Floyd Warshall algorithm goal
The Floyd Warshall algorithm is designed to find shortest paths between every pair of vertices in a weighted graph, including negative weights but no negative cycles.Step 2: Compare with other graph algorithms
Minimum spanning tree algorithms find a tree connecting all vertices with minimum total edge weight, cycle detection finds cycles, and DFS is a traversal method. These are different from Floyd Warshall's all pairs shortest path goal.Final Answer:
To find the shortest paths between all pairs of vertices in a weighted graph -> Option DQuick Check:
Floyd Warshall = All pairs shortest paths [OK]
- Confusing with minimum spanning tree algorithms
- Thinking it only finds shortest path from one source
- Mixing with cycle detection or traversal algorithms
Solution
Step 1: Initialize matrix with infinity
We start with all distances as infinity (i32::MAX) because no edges exist initially.Step 2: Set distance from vertex to itself as zero
Distance from a vertex to itself is zero, so dist[i][i] = 0 for all i.Final Answer:
let mut dist = vec![vec![i32::MAX; 3]; 3]; for i in 0..3 { dist[i][i] = 0; } -> Option BQuick Check:
Init with i32::MAX, diagonal zero [OK]
- Setting diagonal to infinity instead of zero
- Initializing with zeros everywhere
- Mixing up i32::MAX and 0 values
let n = 3;
let mut dist = vec![vec![i32::MAX; n]; n];
for i in 0..n { dist[i][i] = 0; }
dist[0][1] = 4;
dist[1][2] = 3;
dist[0][2] = 10;
for k in 0..n {
for i in 0..n {
for j in 0..n {
if dist[i][k] != i32::MAX && dist[k][j] != i32::MAX {
dist[i][j] = dist[i][j].min(dist[i][k] + dist[k][j]);
}
}
}
}
println!("{}", dist[0][2]);Solution
Step 1: Initial distances
dist[0][2] starts at 10, dist[0][1] = 4, dist[1][2] = 3.Step 2: Update via intermediate vertex 1
Check if path 0->1->2 is shorter: 4 + 3 = 7, which is less than 10, so update dist[0][2] to 7.Final Answer:
7 -> Option AQuick Check:
0->1->2 = 7 < 10 [OK]
- Not updating dist[0][2] via vertex 1
- Confusing initial edge weights with final shortest paths
- Ignoring i32::MAX checks causing overflow
for k in 0..n {
for i in 0..n {
for j in 0..n {
if dist[i][k] + dist[k][j] < dist[i][j] {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}Solution
Step 1: Analyze addition of distances
Adding dist[i][k] + dist[k][j] without checking if either is i32::MAX can cause integer overflow.Step 2: Importance of checks before addition
Proper Floyd Warshall requires checking dist[i][k] != i32::MAX and dist[k][j] != i32::MAX before adding to avoid overflow and incorrect updates.Final Answer:
Missing check for i32::MAX before addition causing overflow -> Option CQuick Check:
Check for infinity before addition to avoid overflow [OK]
- Ignoring overflow from adding i32::MAX
- Changing loop order unnecessarily
- Confusing comparison operators
- Forgetting to initialize diagonal distances
Solution
Step 1: Initial distances
Direct edge 0->3 is 20. Other edges: 0->1=5, 1->2=2, 2->3=1.Step 2: Calculate path 0->1->2->3
Sum is 5 + 2 + 1 = 8, which is less than 20, so shortest path updates to 8.Final Answer:
8 -> Option AQuick Check:
0->1->2->3 = 8 < 20 [OK]
- Choosing direct edge weight without checking intermediate paths
- Adding edges incorrectly
- Ignoring path through multiple vertices
Ready to prove it?
Pass the test and this pattern moves unknown
