Floyd Warshall All Pairs Shortest Path in DSA C++ - 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 the number of points in the graph grows?
Analyze the time complexity of the following code snippet.
void floydWarshall(int graph[][V], int dist[][V]) {
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
}
This code updates shortest distances between all pairs 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.
- How many times: Each loop runs V times, so the inner operation runs V x V x V = V³ times.
As the number of points (V) grows, the number of checks grows very fast because every pair is checked for every possible intermediate point.
| Input Size (V) | Approx. Operations |
|---|---|
| 10 | 1,000 |
| 100 | 1,000,000 |
| 1000 | 1,000,000,000 |
Pattern observation: The operations grow roughly by the cube of the input size, so tripling the points makes the work about 27 times bigger.
Time Complexity: O(V³)
This means the time needed grows very quickly as the number of points increases, because it checks all pairs through all intermediate points.
[X] Wrong: "Since it uses loops, it must be O(V²) because there are two loops for pairs."
[OK] Correct: There are actually three nested loops, so the checks happen V x V x V times, making it O(V³), not O(V²).
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 replaced the triple nested loops with a recursive approach? 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 algorithms find cycles, and DFS is a traversal method. These are different from Floyd Warshall's goal.Final Answer:
To find shortest paths between all pairs of vertices in a weighted graph -> Option AQuick Check:
Floyd Warshall = all pairs shortest paths [OK]
- Confusing Floyd Warshall with minimum spanning tree algorithms
- Thinking it only finds shortest path from one source
- Assuming it detects cycles instead of paths
dist for Floyd Warshall in C++ for a graph with n vertices and adjacency matrix graph?Solution
Step 1: Understand distance matrix initialization
We need to copy each element from the adjacency matrixgraphtodistelement-wise becausedistis a 2D array and direct assignment is not allowed in C++.Step 2: Analyze each option
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) dist[i][j] = graph[i][j]; uses nested loops to copy each element correctly. for (int i = 0; i < n; i++) dist[i] = graph[i]; tries to assign a row pointer which is invalid for 2D arrays. dist = graph; tries direct assignment which is invalid for arrays. dist = new int[n][n]; only allocates memory but does not initialize values.Final Answer:
for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) dist[i][j] = graph[i][j]; -> Option BQuick Check:
Element-wise copy needed = for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) dist[i][j] = graph[i][j]; [OK]
- Trying to assign 2D arrays directly
- Copying only row pointers instead of elements
- Not initializing distance matrix before algorithm
int graph[3][3] = {
{0, 5, 999},
{50, 0, 15},
{30, 999, 0}
};Assuming 999 represents no direct edge.
Solution
Step 1: Initialize distance matrix
Start with dist = graph:
dist = [[0,5,999],[50,0,15],[30,999,0]]Step 2: Update distances using Floyd Warshall
Check if going through vertex 0 improves paths:
dist[1][2] = min(15, dist[1][0]+dist[0][2]) = min(15, 50+999)=15 (no change)
dist[2][1] = min(999, dist[2][0]+dist[0][1]) = min(999, 30+5)=35 (updated)
Check through vertex 1:
dist[0][2] = min(999, dist[0][1]+dist[1][2]) = min(999, 5+15)=20 (updated)
dist[2][2] = min(0, dist[2][1]+dist[1][2]) = min(0, 35+15)=0 (no change)
Check through vertex 2:
dist[1][0] = min(50, dist[1][2]+dist[2][0]) = min(50, 15+30)=45 (updated)Final Answer:
[[0, 5, 20], [45, 0, 15], [30, 35, 0]] -> Option DQuick Check:
Updated shortest paths matrix = [[0, 5, 20], [45, 0, 15], [30, 35, 0]] [OK]
- Not updating paths through intermediate vertices
- Confusing no edge (999) with zero
- Missing updates for reverse paths
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (dist[i][k] + dist[k][j] < dist[i][j])
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}Solution
Step 1: Understand potential overflow in addition
If dist[i][k] or dist[k][j] is infinity (representing no path), adding them causes incorrect results or overflow.Step 2: Fix by checking for infinity before addition
Before adding dist[i][k] + dist[k][j], ensure both are not infinity to avoid invalid updates.Final Answer:
Check if dist[i][k] and dist[k][j] are not infinity before adding -> Option AQuick Check:
Prevent invalid addition by checking infinity [OK]
- Ignoring infinity checks causing wrong updates
- Changing loop order incorrectly
- Using max instead of min for shortest path
int graph[4][4] = {
{0, 3, 999, 7},
{8, 0, 2, 999},
{5, 999, 0, 1},
{2, 999, 999, 0}
};Use Floyd Warshall to find the shortest path distance from vertex 0 to vertex 3 after all updates. What is the shortest distance?
Solution
Step 1: Initialize distance matrix
Start with dist = graph:
dist = [[0,3,999,7],[8,0,2,999],[5,999,0,1],[2,999,999,0]]Step 2: Update distances through intermediate vertices
Check paths through vertex 0:
dist[1][3] = min(999, dist[1][0]+dist[0][3]) = min(999, 8+7)=15
dist[2][1] = min(999, dist[2][0]+dist[0][1]) = min(999, 5+3)=8
dist[3][1] = min(999, dist[3][0]+dist[0][1]) = min(999, 2+3)=5
Check paths through vertex 1:
dist[0][2] = min(999, dist[0][1]+dist[1][2]) = min(999, 3+2)=5
dist[0][3] = min(7, dist[0][1]+dist[1][3]) = min(7, 3+15)=7
dist[3][2] = min(999, dist[3][1]+dist[1][2]) = min(999, 5+2)=7
Check paths through vertex 2:
dist[1][3] = min(15, dist[1][2]+dist[2][3]) = min(15, 2+1)=3 (updated)
dist[0][3] = min(7, dist[0][2]+dist[2][3]) = min(7, 5+1)=6 (updated)
Check paths through vertex 3:
dist[2][0] = min(5, dist[2][3]+dist[3][0]) = min(5, 1+2)=3 (updated)Final Answer:
6 -> Option CQuick Check:
Shortest path 0 to 3 = 6 [OK]
- Not updating paths through all intermediate vertices
- Missing shorter path updates
- Confusing direct edge with shortest path
Ready to prove it?
Pass the test and this pattern moves unknown
