Given a weighted Directed Acyclic Graph (DAG) with V vertices numbered from 0 to V - 1, represented by edges[][], where edges[i] = [u, v, w] denotes a directed edge from u to v with weight w, and a source vertex src.
Return the distance array, where the value at index i represents the longest distance from src to vertex i.
If a vertex is unreachable from s, store INT_MIN for that vertex. The driver code will automatically display INT_MIN as INF.
Examples :
Input: V = 4, src = 0, edges[][] = [[0, 1, 1], [0, 2, 1], [1, 2, 5], [3, 1, 2], [3, 2, -1]] Output: [0, 1, 6, INF] Explanation: The longest distance of vertex 1 from 0 is 1, vertex 2 is 6 and vertex 3 is unreachable so INF.
Input: V = 5, src = 1, edges[][] = [[0, 1, 1], [0, 2, 2], [1, 4, 4], [3, 2, -1], [4, 2, 3], [4, 3, 6]] Output: [INF, 0, 9, 10, 4] Explanation: The vertex 0 is not reachable from vertex 1 so its distance is INF, for 2 it is 9, for 3 it is 10, and for 4 it is 4.
[Naive Approach] DFS Traversal of All Possible Paths - O(2 ^ V) Time and O(V) Space
The idea is to start a DFS from the source vertex and explore every possible path in the DAG. For each path, maintain the current path sum and update the maximum distance of every reachable vertex. Since a DAG can contain exponentially many paths, this approach is inefficient for large graphs.
Working of Approach:
Build an adjacency list from the given edge list to represent the directed graph.
Initialize a distance array with INT_MIN to mark all vertices as unreachable, and start DFS from the source with distance 0.
During DFS, update the current node's distance with the maximum distance reached so far.
Recursively visit every outgoing neighbor, passing the accumulated distance (current distance + edge weight).
Since the graph is a DAG, DFS explores all possible paths, and each node stores the maximum path distance from the source.
Finally, return the distance array, where INT_MIN values are displayed as INF for unreachable vertices.
C++
#include<iostream>#include<vector>#include<algorithm>#include<limits>usingnamespacestd;voiddfs(intnode,intcurrDist,vector<vector<pair<int,int>>>&adj,vector<int>&dist){dist[node]=max(dist[node],currDist);for(auto&it:adj[node]){intv=it.first;intwt=it.second;dfs(v,currDist+wt,adj,dist);}}vector<int>maxDistance(intV,intsrc,vector<vector<int>>&edges){// Build adjacency listvector<vector<pair<int,int>>>adj(V);for(auto&edge:edges){intu=edge[0];intv=edge[1];intwt=edge[2];adj[u].push_back({v,wt});}// Initialize distancesvector<int>dist(V,INT_MIN);// Start DFS from sourcedfs(src,0,adj,dist);returndist;}intmain(){intV=5,src=1;vector<vector<int>>edges={{0,1,1},{0,2,2},{1,4,4},{3,2,-1},{4,2,3},{4,3,6}};vector<int>ans=maxDistance(V,src,edges);cout<<"[";for(inti=0;i<ans.size();i++){if(ans[i]==INT_MIN)cout<<"INF";elsecout<<ans[i];if(i!=ans.size()-1)cout<<",";}cout<<"]";return0;}
[Expected Approach] Kahn's Topological Sort with Dynamic Programming - O(V + E) Time and O(V + E) Space
The key observation is the property of a topological ordering. All predecessors (incoming neighbors) of a vertex are processed before the vertex itself.
The idea is to first obtain a topological ordering of the DAG using Kahn's Algorithm. Then process vertices in topological order and relax all outgoing edges. Since every vertex appears after its predecessors in the ordering, the longest distance to a vertex is already computed before it is processed.
Why this Approach works?
Consider the DAG:
One valid topological order is: 0 -> 1 -> 2 -> 3
Process 0: dist[1] = 2, dist[2] = 3
Process 1: dist[3] = 2 + 4 = 6
Process 2: dist[3] = max(6, 3 + 5) = 8
Process 3
Now, you will notice that when vertex 3 is processed, both of its predecessors (1 and 2) have already been processed. Therefore, the longest distance to 3 has already been determined (8), and no future vertex can provide another path to 3 because that would violate the topological ordering. This is exactly why processing vertices in topological order guarantees that the longest distance to a vertex is finalized before the vertex itself is processed.
Let us understand with example: Input: V = 5, src = 1, edges[][] = [[0, 1, 1], [0, 2, 2], [1, 4, 4], [3, 2, -1], [4, 2, 3], [4, 3, 6]]
The topological order of the DAG is obtained as [0, 1, 4, 3, 2].
Initialize the distance array with INT_MIN and set the source distance: dist = [-INF, 0, -INF, -INF, -INF].
Vertex 0 is unreachable from the source, so it is skipped.
Process vertex 1 and relax edge (1 -> 4): dist[4] = 4.
Process vertex 4 and relax edges (4 -> 2) and (4 -> 3): dist = [-INF, 0, 7, 10, 4].
Process vertex 3 and relax edge (3 -> 2), updating dist[2] from 7 to 9.
After replacing unreachable values (INT_MIN) with INF for display, the final output becomes [INF, 0, 9, 10, 4].
C++
#include<iostream>#include<vector>#include<queue>#include<climits>usingnamespacestd;vector<int>maxDistance(intV,intsrc,vector<vector<int>>&edges){// Build the adjacency list and indegree arrayvector<vector<pair<int,int>>>g(V);vector<int>indegree(V,0);for(auto&ed:edges){intu=ed[0];intv=ed[1];intwt=ed[2];g[u].push_back({v,wt});indegree[v]++;}// Kahn's Algorithm to obtain a topological orderingqueue<int>q;for(inti=0;i<V;i++){if(indegree[i]==0)q.push(i);}vector<int>topoOrder;while(!q.empty()){intnode=q.front();q.pop();topoOrder.push_back(node);for(auto&it:g[node]){intv=it.first;if(--indegree[v]==0)q.push(v);}}// Initialize all distances as unreachablevector<int>dist(V,INT_MIN);dist[src]=0;// Process vertices in topological order and// relax outgoing edges to compute longest pathsfor(intnode:topoOrder){// Skip unreachable verticesif(dist[node]==INT_MIN)continue;for(auto&it:g[node]){intv=it.first;intwt=it.second;dist[v]=max(dist[v],dist[node]+wt);}}returndist;}intmain(){intV=5,src=1;vector<vector<int>>edges={{0,1,1},{0,2,2},{1,4,4},{3,2,-1},{4,2,3},{4,3,6}};vector<int>ans=maxDistance(V,src,edges);cout<<"[";for(inti=0;i<ans.size();i++){if(ans[i]==INT_MIN)cout<<"INF";elsecout<<ans[i];if(i!=ans.size()-1)cout<<", ";}cout<<"]";return0;}
fromcollectionsimportdequedefmaxDistance(V,src,edges):# Build the adjacency list and indegree arrayg=[[]for_inrange(V)]indegree=[0]*Vforu,v,wtinedges:g[u].append((v,wt))indegree[v]+=1# Kahn's Algorithm to obtain a topological orderingq=deque()foriinrange(V):ifindegree[i]==0:q.append(i)topoOrder=[]whileq:node=q.popleft()topoOrder.append(node)forv,wting[node]:indegree[v]-=1ifindegree[v]==0:q.append(v)# Initialize all distances as unreachableINT_MIN=-(2**31)dist=[INT_MIN]*Vdist[src]=0# Process vertices in topological order and# relax outgoing edges to compute longest pathsfornodeintopoOrder:# Skip unreachable verticesifdist[node]==INT_MIN:continueforv,wting[node]:dist[v]=max(dist[v],dist[node]+wt)returndistif__name__=="__main__":V=5src=1edges=[[0,1,1],[0,2,2],[1,4,4],[3,2,-1],[4,2,3],[4,3,6]]ans=maxDistance(V,src,edges)print("[",end="")foriinrange(len(ans)):ifans[i]==-(2**31):print("INF",end="")else:print(ans[i],end="")ifi!=len(ans)-1:print(", ",end="")print("]")
functionmaxDistance(V,src,edges){// Build the adjacency list and indegree arrayletg=Array.from({length:V},()=>[]);letindegree=newArray(V).fill(0);for(letedofedges){letu=ed[0];letv=ed[1];letwt=ed[2];g[u].push([v,wt]);indegree[v]++;}// Kahn's Algorithm to obtain a topological orderingletq=[];for(leti=0;i<V;i++){if(indegree[i]===0){q.push(i);}}lettopoOrder=[];letfront=0;while(front<q.length){letnode=q[front++];topoOrder.push(node);for(let[nxt,wt]ofg[node]){indegree[nxt]--;if(indegree[nxt]===0){q.push(nxt);}}}// Initialize all distances as unreachableconstINT_MIN=-2147483648;letdist=newArray(V).fill(INT_MIN);dist[src]=0;// Process vertices in topological order and// relax outgoing edges to compute longest pathsfor(letnodeoftopoOrder){// Skip unreachable verticesif(dist[node]===INT_MIN){continue;}for(let[nxt,wt]ofg[node]){dist[nxt]=Math.max(dist[nxt],dist[node]+wt);}}returndist;}// Driver codeletV=5;letsrc=1;letedges=[[0,1,1],[0,2,2],[1,4,4],[3,2,-1],[4,2,3],[4,3,6]];letans=maxDistance(V,src,edges);process.stdout.write("[");for(leti=0;i<ans.length;i++){if(ans[i]===-2147483648){process.stdout.write("INF");}else{process.stdout.write(ans[i].toString());}if(i!==ans.length-1){process.stdout.write(", ");}}process.stdout.write("]");