Shortest Path in DAG Using Topological Order in DSA C++ - Time & Space Complexity
We want to understand how the time needed to find the shortest path in a Directed Acyclic Graph (DAG) grows as the graph gets bigger.
Specifically, how the steps increase when using topological order to find shortest paths.
Analyze the time complexity of the following code snippet.
// Find shortest paths in DAG using topological order
void shortestPath(int src, vector> adj[], int V) {
vector dist(V, INT_MAX);
dist[src] = 0;
vector topo = topologicalSort(V, adj);
for (int u : topo) {
if (dist[u] != INT_MAX) {
for (auto &edge : adj[u]) {
int v = edge.first, w = edge.second;
if (dist[u] + w < dist[v])
dist[v] = dist[u] + w;
}
}
}
}
This code finds shortest distances from a source node to all others in a DAG by first sorting nodes topologically, then relaxing edges in order.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The nested loops: outer loop over all vertices in topological order, inner loop over all edges from each vertex.
- How many times: Outer loop runs V times (number of vertices), inner loop runs once per edge from each vertex, totaling E times (number of edges).
As the graph grows, the number of vertices (V) and edges (E) increase, affecting the steps.
| Input Size (V, E) | Approx. Operations |
|---|---|
| 10 vertices, 15 edges | About 10 + 15 = 25 steps |
| 100 vertices, 200 edges | About 100 + 200 = 300 steps |
| 1000 vertices, 5000 edges | About 1000 + 5000 = 6000 steps |
Pattern observation: The total steps grow roughly in proportion to the sum of vertices and edges.
Time Complexity: O(V + E)
This means the time needed grows linearly with the number of vertices plus the number of edges in the graph.
[X] Wrong: "The time depends on the number of paths or cycles in the graph."
[OK] Correct: Since the graph is acyclic, there are no cycles, and the algorithm processes each vertex and edge only once, so paths or cycles do not increase time.
Understanding this time complexity helps you explain why topological sorting is efficient for shortest paths in DAGs, a common interview topic.
"What if the graph had cycles? How would the time complexity and approach change?"
Practice
Solution
Step 1: Understand topological order in DAG
Topological order arranges vertices so that all edges go from earlier to later vertices, allowing linear processing.Step 2: Use topological order for shortest path
Processing vertices in this order ensures each vertex is relaxed once, avoiding revisits and cycles.Final Answer:
It allows processing vertices in a linear order without revisiting nodes. -> Option AQuick Check:
Topological order = linear processing without revisits [OK]
- Thinking it works for graphs with cycles
- Confusing shortest path with longest path
- Assuming it works for undirected graphs
n vertices, assuming source vertex is 0?Solution
Step 1: Initialize distances with maximum value
Distances should start as infinity (INT_MAX) except source which is 0.Step 2: Check code correctness
std::vector<int> dist(n, INT_MAX); dist[0] = 0; correctly sets all distances to INT_MAX and source distance to 0.Final Answer:
std::vector<int> dist(n, INT_MAX); dist[0] = 0; -> Option BQuick Check:
Distance init = INT_MAX except source 0 [OK]
- Setting source distance to INT_MAX
- Initializing distances to zero
- Not using vector or uninitialized array
0 -> 1 (2), 0 -> 2 (4), 1 -> 2 (1), 1 -> 3 (7), 2 -> 3 (3)Using topological order starting from vertex 0, what is the shortest distance to vertex 3?
Solution
Step 1: Find topological order and initialize distances
Topological order: 0, 1, 2, 3. Initialize dist[0]=0, others = infinity.Step 2: Relax edges in topological order
From 0: dist[1]=2, dist[2]=4
From 1: dist[2]=min(4, 2+1=3)=3, dist[3]=2+7=9
From 2: dist[3]=min(9, 3+3=6)=6Final Answer:
6 -> Option AQuick Check:
Shortest path to 3 = 6 [OK]
- Not updating dist[2] to 3 via vertex 1
- Ignoring relaxation from vertex 2 to 3
- Using wrong topological order
std::vector<int> dist(n, INT_MAX);
dist[source] = 0;
for (int u : topoOrder) {
for (auto &edge : graph[u]) {
int v = edge.first, w = edge.second;
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
}
}
}Solution
Step 1: Analyze relaxation condition
The code adds w to dist[u] without checking if dist[u] is INT_MAX, causing overflow.Step 2: Identify missing check
Before relaxing edges, must check dist[u] != INT_MAX to avoid invalid addition.Final Answer:
The code does not check if dist[u] is INT_MAX before adding w. -> Option DQuick Check:
Check dist[u] != INT_MAX before relaxation [OK]
- Assuming initialization is wrong
- Thinking topological order is incorrect
- Forgetting to set source distance
0->1(3), 0->2(6), 1->2(4), 1->3(4), 2->3(8), 3->4(2)Using topological order, what is the shortest path distance from vertex 0 to vertex 4?
Solution
Step 1: Determine topological order and initialize distances
Topological order: 0,1,2,3,4. Initialize dist[0]=0, others = infinity.Step 2: Relax edges in order
From 0: dist[1]=3, dist[2]=6
From 1: dist[2]=min(6,3+4=7)=6, dist[3]=3+4=7
From 2: dist[3]=min(7,6+8=14)=7
From 3: dist[4]=7+2=9Final Answer:
9 -> Option CQuick Check:
Shortest path to 4 = 9 [OK]
- Not updating dist[3] correctly
- Choosing longer path via vertex 2
- Misordering topological sort
Ready to prove it?
Pass the test and this pattern moves unknown
