Given a weighted Directed Acyclic Graph (DAG) with n nodes and m edges, where each edge is represented as [u, v, w] (a directed edge from u to v with weight w), and a source node src, find the shortest distance from src to all other nodes.
Note: If it is impossible to reach a node from source node, then mark the distance as -1.
Input: V = 4, E = 2, edges = [[0,1,2], [0,2,1]] Output: [0, 2, 1, -1] Explanation: Shortest path from 0 to 1 is 0->1 with edge weight 2. The shortest path from 0 to 2 is 0->2 with edge weight 1. There is no way we can reach 3, so it's -1 for 3.
For a general weighted graph, we can calculate single source shortest distances in O(V + E) time using Bellman–Ford Algorithm. For a graph with no negative weights, we can do better and calculate single source shortest distances in O(E + VLogV) time using Dijkstra's algorithm.
[Expected Approach] Using Topological Sort and Edge Relaxation - O(V + E) Time O(V + E) Space
Can we do even better for Directed Acyclic Graph (DAG)?
For a DAG, we can compute shortest paths in O(V + E) time using topological sorting. Initialize distances (source = 0, others = ∞), get the topological order, and relax edges in that order. Since the graph has no cycles, each edge is processed once, making it the most efficient approach.
We initialize distances to all vertices as infinite and distance to source as 0, then we find a topological sorting of the graph. Topological Sorting of a graph represents a linear ordering of the graph (See below, figure). Once we have topological order (or linear representation), we one by one process all vertices in topological order. For every vertex being processed, we update distances of its adjacent using distance of current vertex.
Following is complete algorithm for finding shortest distances.
Initialize dist[] = {INF, INF, ....} and dist[s] = 0 where s is the source vertex.
Create a topological order of all vertices.
Do following for every vertex u in topological order. ...........Do following for every adjacent vertex v of u ..................if (dist[v] > dist[u] + weight(u, v)) ...........................dist[v] = dist[u] + weight(u, v)
C++
#include<bits/stdc++.h>usingnamespacestd;// Function to perform Topological Sort using DFSvoidtopoSort(intnode,vector<int>&vis,stack<int>&st,vector<vector<pair<int,int>>>&adj){vis[node]=1;// Traverse all adjacent nodesfor(auto&it:adj[node]){if(!vis[it.first]){topoSort(it.first,vis,st,adj);}}// Push node to stack after visiting all neighborsst.push(node);}// Function to find shortest path in DAGvector<int>shortestPath(intV,intE,vector<vector<int>>&edges){// Adjacency list: {node -> {adjacent_node, weight}}vector<vector<pair<int,int>>>adj(V);// Build the graph from given edgesfor(auto&e:edges){intu=e[0];intv=e[1];intwt=e[2];adj[u].push_back({v,wt});}// Visited array for DFSvector<int>vis(V,0);stack<int>st;//Perform Topological Sort for all nodesfor(inti=0;i<V;i++){if(!vis[i]){topoSort(i,vis,st,adj);}}//Initialize distancesconstintINF=1e9;vector<int>dist(V,INF);dist[0]=0;//Process nodes in topological orderwhile(!st.empty()){intnode=st.top();st.pop();// If node is reachableif(dist[node]!=INF){// Relax all adjacent edgesfor(auto&it:adj[node]){intv=it.first;intwt=it.second;// Update distance if shorter path is foundif(dist[node]+wt<dist[v]){dist[v]=dist[node]+wt;}}}}// Mark unreachable nodes as -1for(inti=0;i<V;i++){if(dist[i]==INF){dist[i]=-1;}}returndist;}intmain(){intV=6;intE=7;// Edge list: {u, v, weight}vector<vector<int>>edges={{0,1,2},{0,4,1},{4,5,4},{4,2,2},{1,2,3},{2,3,6},{5,3,1}};vector<int>result=shortestPath(V,E,edges);for(intx:result){cout<<x<<" ";}return0;}
C
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>#include<limits.h>#define MAX_NODES 100typedefstructEdge{intv,wt;}Edge;typedefstructNode{Edge*edges;intsize;}Node;Node*adj[MAX_NODES];intvis[MAX_NODES];intdist[MAX_NODES];// Function to perform Topological Sort using DFSvoidtopoSort(intnode,intvis[],intst[],int*top,Node*adj[]){vis[node]=1;for(inti=0;i<adj[node]->size;i++){Edgeit=adj[node]->edges[i];if(!vis[it.v]){topoSort(it.v,vis,st,top,adj);}}st[(*top)++]=node;}// Function to find shortest path in DAGvoidshortestPath(intV,intE,intedges[][3]){// Initialize adjacency listfor(inti=0;i<V;i++){adj[i]=(Node*)malloc(sizeof(Node));adj[i]->edges=(Edge*)malloc(sizeof(Edge)*MAX_NODES);adj[i]->size=0;}// Build the graph from given edgesfor(inti=0;i<E;i++){intu=edges[i][0];intv=edges[i][1];intwt=edges[i][2];adj[u]->edges[adj[u]->size++]=(Edge){v,wt};}// Visited array for DFSfor(inti=0;i<V;i++){vis[i]=0;}intst[V];inttop=0;// Perform Topological Sort for all nodesfor(inti=0;i<V;i++){if(!vis[i]){topoSort(i,vis,st,&top,adj);}}// Initialize distancesfor(inti=0;i<V;i++){dist[i]=INT_MAX;}dist[0]=0;// Process nodes in topological orderfor(inti=top-1;i>=0;i--){intnode=st[i];// If node is reachableif(dist[node]!=INT_MAX){// Relax all adjacent edgesfor(intj=0;j<adj[node]->size;j++){Edgeit=adj[node]->edges[j];intv=it.v;intwt=it.wt;// Update distance if shorter path is foundif(dist[node]+wt<dist[v]){dist[v]=dist[node]+wt;}}}}// Mark unreachable nodes as -1for(inti=0;i<V;i++){if(dist[i]==INT_MAX){dist[i]=-1;}}// Print the resultfor(inti=0;i<V;i++){printf("%d ",dist[i]);}}intmain(){intV=6;intE=7;// Edge list: {u, v, weight}intedges[][3]={{0,1,2},{0,4,1},{4,5,4},{4,2,2},{1,2,3},{2,3,6},{5,3,1}};shortestPath(V,E,edges);return0;}
Java
importjava.util.*;publicclassGfG{// Function to perform Topological Sort using DFSstaticvoidtopoSort(intnode,boolean[]vis,Stack<Integer>st,ArrayList<ArrayList<int[]>>adj){vis[node]=true;// Traverse all adjacent nodesfor(int[]it:adj.get(node)){if(!vis[it[0]]){topoSort(it[0],vis,st,adj);}}// Push node to stack after visiting all neighborsst.push(node);}// Function to find shortest path in DAGstaticint[]shortestPath(intV,intE,int[][]edges){// Adjacency list: {node -> {adjacent_node, weight}}ArrayList<ArrayList<int[]>>adj=newArrayList<>();for(inti=0;i<V;i++){adj.add(newArrayList<>());}// Build the graph from given edgesfor(int[]e:edges){intu=e[0];intv=e[1];intwt=e[2];adj.get(u).add(newint[]{v,wt});}// Visited array for DFSboolean[]vis=newboolean[V];Stack<Integer>st=newStack<>();// Perform Topological Sort for all nodesfor(inti=0;i<V;i++){if(!vis[i]){topoSort(i,vis,st,adj);}}// Initialize distancesfinalintINF=(int)1e9;int[]dist=newint[V];Arrays.fill(dist,INF);dist[0]=0;// Process nodes in topological orderwhile(!st.isEmpty()){intnode=st.pop();// If node is reachableif(dist[node]!=INF){// Relax all adjacent edgesfor(int[]it:adj.get(node)){intv=it[0];intwt=it[1];// Update distance if shorter path is foundif(dist[node]+wt<dist[v]){dist[v]=dist[node]+wt;}}}}// Mark unreachable nodes as -1for(inti=0;i<V;i++){if(dist[i]==INF){dist[i]=-1;}}returndist;}publicstaticvoidmain(String[]args){intV=6;intE=7;int[][]edges={{0,1,2},{0,4,1},{4,5,4},{4,2,2},{1,2,3},{2,3,6},{5,3,1}};int[]result=shortestPath(V,E,edges);for(intx:result){System.out.print(x+" ");}}}
Python
fromcollectionsimportdefaultdict# Function to perform Topological Sort using DFSdeftopoSort(node,vis,st,adj):vis[node]=True# Traverse all adjacent nodesforitinadj[node]:ifnotvis[it[0]]:topoSort(it[0],vis,st,adj)# Push node to stack after visiting all neighborsst.append(node)# Function to find shortest path in DAGdefshortestPath(V,E,edges):# Adjacency list: {node -> {adjacent_node, weight}}adj=defaultdict(list)# Build the graph from given edgesforeinedges:u,v,wt=eadj[u].append((v,wt))# Visited array for DFSvis=[False]*Vst=[]# Perform Topological Sort for all nodesforiinrange(V):ifnotvis[i]:topoSort(i,vis,st,adj)# Initialize distancesINF=10**9dist=[INF]*Vdist[0]=0# Process nodes in topological orderwhilest:node=st.pop()# If node is reachableifdist[node]!=INF:# Relax all adjacent edgesforv,wtinadj[node]:# Update distance if shorter path is foundifdist[node]+wt<dist[v]:dist[v]=dist[node]+wt# Mark unreachable nodes as -1foriinrange(V):ifdist[i]==INF:dist[i]=-1returndistif__name__=='__main__':V=6E=7edges=[(0,1,2),(0,4,1),(4,5,4),(4,2,2),(1,2,3),(2,3,6),(5,3,1)]result=shortestPath(V,E,edges)print(' '.join(map(str,result)))
C#
usingSystem;usingSystem.Collections.Generic;classGfG{// Function to perform Topological Sort using DFSstaticvoidtopoSort(intnode,List<int>vis,Stack<int>st,List<List<Tuple<int,int>>>adj){vis[node]=1;// Traverse all adjacent nodesforeach(varitinadj[node]){if(vis[it.Item1]==0){topoSort(it.Item1,vis,st,adj);}}// Push node to stack after visiting all neighborsst.Push(node);}// Function to find shortest path in DAGstaticList<int>shortestPath(intV,intE,List<List<int>>edges){// Adjacency list: {node -> {adjacent_node, weight}}List<List<Tuple<int,int>>>adj=newList<List<Tuple<int,int>>>();for(inti=0;i<V;i++){adj.Add(newList<Tuple<int,int>>(V));}// Build the graph from given edgesforeach(vareinedges){intu=e[0];intv=e[1];intwt=e[2];adj[u].Add(newTuple<int,int>(v,wt));}// Visited array for DFSList<int>vis=newList<int>(V);for(inti=0;i<V;i++){vis.Add(0);}Stack<int>st=newStack<int>();//Perform Topological Sort for all nodesfor(inti=0;i<V;i++){if(vis[i]==0){topoSort(i,vis,st,adj);}}//Initialize distancesconstintINF=1000000000;List<int>dist=newList<int>(V);for(inti=0;i<V;i++){dist.Add(INF);}dist[0]=0;//Process nodes in topological orderwhile(st.Count>0){intnode=st.Pop();// If node is reachableif(dist[node]!=INF){// Relax all adjacent edgesforeach(varitinadj[node]){intv=it.Item1;intwt=it.Item2;// Update distance if shorter path is foundif(dist[node]+wt<dist[v]){dist[v]=dist[node]+wt;}}}}// Mark unreachable nodes as -1for(inti=0;i<V;i++){if(dist[i]==INF){dist[i]=-1;}}returndist;}staticvoidMain(string[]args){intV=6;intE=7;// Edge list: {u, v, weight}List<List<int>>edges=newList<List<int>>(){newList<int>{0,1,2},newList<int>{0,4,1},newList<int>{4,5,4},newList<int>{4,2,2},newList<int>{1,2,3},newList<int>{2,3,6},newList<int>{5,3,1}};List<int>result=shortestPath(V,E,edges);foreach(intxinresult){Console.Write(x+" ");}}}
JavaScript
functiontopoSort(node,vis,st,adj){vis[node]=1;// Traverse all adjacent nodesfor(letitofadj[node]){if(!vis[it[0]]){topoSort(it[0],vis,st,adj);}}// Push node to stack after visiting all neighborsst.push(node);}// Function to find shortest path in DAGfunctionshortestPath(V,E,edges){// Adjacency list: {node -> {adjacent_node, weight}}letadj=Array.from({length:V},()=>[]);// Build the graph from given edgesfor(leteofedges){letu=e[0];letv=e[1];letwt=e[2];adj[u].push([v,wt]);}// Visited array for DFSletvis=Array(V).fill(0);letst=[];//Perform Topological Sort for all nodesfor(leti=0;i<V;i++){if(!vis[i]){topoSort(i,vis,st,adj);}}//Initialize distancesconstINF=1e9;letdist=Array(V).fill(INF);dist[0]=0;//Process nodes in topological orderwhile(st.length>0){letnode=st.pop();// If node is reachableif(dist[node]!==INF){// Relax all adjacent edgesfor(letitofadj[node]){letv=it[0];letwt=it[1];// Update distance if shorter path is foundif(dist[node]+wt<dist[v]){dist[v]=dist[node]+wt;}}}}// Mark unreachable nodes as -1for(leti=0;i<V;i++){if(dist[i]===INF){dist[i]=-1;}}returndist;}letV=6;letE=7;// Edge list: {u, v, weight}letedges=[[0,1,2],[0,4,1],[4,5,4],[4,2,2],[1,2,3],[2,3,6],[5,3,1]];letresult=shortestPath(V,E,edges);for(letxofresult){console.log(x+" ");}
Output
0 2 3 6 1 5
Time Complexity: O(V + E), we perform topological sort and relax each edge once Space Complexity: O(V + E) , for graph storage and distance array