{"id":319,"date":"2025-06-17T20:20:50","date_gmt":"2025-06-17T14:50:50","guid":{"rendered":"https:\/\/codeanddebug.in\/blog\/?p=319"},"modified":"2025-06-17T20:24:26","modified_gmt":"2025-06-17T14:54:26","slug":"shortest-path-in-a-weighted-dag-topological-sort","status":"publish","type":"post","link":"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/","title":{"rendered":"Shortest Path in a Weighted Directed Acyclic Graph | Topological-Sort + Relaxation | Python"},"content":{"rendered":"\n<p>Learn how to find single source shortest path in a weighted directed acyclic graph (DAG) in linear time. We explain topological sorting by DFS, step-by-step edge relaxation, include fully-commented Python code, a hand dry-run, and clear Big-O analysis.<\/p>\n\n\n\n<p>Here&#8217;s the [<strong><a href=\"https:\/\/www.geeksforgeeks.org\/problems\/shortest-path-in-undirected-graph\/1\" target=\"_blank\" rel=\"noreferrer noopener\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\"><span style=\"text-decoration: underline;\">Problem Link<\/span><\/mark><\/a><\/strong>] to begin with.<\/p>\n\n\n<div style=\"max-width: -moz-fit-content; \" class=\"wp-block-ub-table-of-contents-block ub_table-of-contents ub_table-of-contents-collapsed\" id=\"ub_table-of-contents-31cd1114-8cf8-4a9c-b06e-996aeed542d5\" data-linktodivider=\"false\" data-showtext=\"show\" data-hidetext=\"hide\" data-scrolltype=\"auto\" data-enablesmoothscroll=\"true\" data-initiallyhideonmobile=\"false\" data-initiallyshow=\"false\"><div class=\"ub_table-of-contents-header-container\" style=\"\">\n\t\t\t<div class=\"ub_table-of-contents-header\" style=\"text-align: left; \">\n\t\t\t\t<div class=\"ub_table-of-contents-title\">Contents:<\/div>\n\t\t\t\t<div class=\"ub_table-of-contents-header-toggle\">\n\t\t\t<div class=\"ub_table-of-contents-toggle\" style=\"\">\n\t\t\t\u00a0[<a class=\"ub_table-of-contents-toggle-link\" href=\"#\" style=\"\">show<\/a>]\n\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div><div class=\"ub_table-of-contents-extra-container\" style=\"\">\n\t\t\t<div class=\"ub_table-of-contents-container ub_table-of-contents-1-column ub-hide\">\n\t\t\t\t<ul style=\"\"><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#0-1-what-does-the-problem-ask\" style=\"\">1. What does the problem ask?<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#1-2-quick-example\" style=\"\">2. Quick example<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#2-3-intuition-amp-approach\" style=\"\">3. Intuition &amp; approach<\/a><ul><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#3-31-why-topological-sort\" style=\"\">3.1 Why topological sort?<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#4-32-algorithm-steps\" style=\"\">3.2 Algorithm steps<\/a><\/li><\/ul><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#5-4-python-code\" style=\"\">4. Python code<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#6-5-detailed-step-by-step-explanation\" style=\"\">5. Detailed step-by-step explanation<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#7-6-dry-run-on-the-sample-graph\" style=\"\">6. Dry run on the sample graph<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#8-7-complexity-analysis\" style=\"\">7. Complexity analysis<\/a><\/li><li style=\"\"><a href=\"https:\/\/codeanddebug.in\/blog\/shortest-path-in-a-weighted-dag-topological-sort\/#9-8conclusion\" style=\"\">8.Conclusion<\/a><\/li><\/ul>\n\t\t\t<\/div>\n\t\t<\/div><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"0-1-what-does-the-problem-ask\">1. What does the problem ask?<\/h2>\n\n\n\n<p>Given<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>V<\/code> \u00ad\u2013 number of vertices labeled <code>0 \u2026 V-1<\/code><\/li>\n\n\n\n<li><code>E<\/code> \u00ad\u2013 number of directed edges<\/li>\n\n\n\n<li><code>edges[i] = [u, v, w]<\/code> \u00ad\u2013 an edge <strong>from<\/strong> <code>u<\/code> <strong>to<\/strong> <code>v<\/code> with positive weight <code>w<\/code><\/li>\n<\/ul>\n\n\n\n<p>return an array <code>distance<\/code> where<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>distance[i]<\/code> = length of the <strong>shortest path from source 0 to vertex i<\/strong><\/li>\n\n\n\n<li>If vertex <code>i<\/code> is unreachable, store <code>-1<\/code>.<\/li>\n<\/ul>\n\n\n\n<p>Because the graph is a <strong>directed acyclic graph (DAG)<\/strong>, there are <strong>no cycles<\/strong>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"1-2-quick-example\">2. Quick example<\/h2>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"V = 6\nedges = [\n  [0,1,2], [0,4,1],\n  [1,2,3], [4,2,2],\n  [2,3,6], [4,5,4], [5,3,1]\n]\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">V = <\/span><span style=\"color: #B5CEA8\">6<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">edges = [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  [<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">], [<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  [<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">], [<\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">],<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  [<\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">6<\/span><span style=\"color: #D4D4D4\">], [<\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">5<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\">], [<\/span><span style=\"color: #B5CEA8\">5<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">,<\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">]<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>One set of shortest distances from source <code>0<\/code> is<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"[0, 2, 3, 6, 1, 5]\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">2<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">3<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">6<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">5<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>0 \u2192 4 \u2192 2 \u2192 \u2026 is cheaper than 0 \u2192 1 \u2192 2, etc.<\/li>\n\n\n\n<li>Vertex 3 is reached through 0 \u2192 4 \u2192 5 \u2192 3 with total weight 6.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"2-3-intuition-amp-approach\">3. Intuition &amp; approach<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"3-31-why-topological-sort\">3.1 Why topological sort?<\/h3>\n\n\n\n<p>In a DAG you can line up vertices so that <strong>every edge goes left-to-right<\/strong>.<br>If you relax (update) edges <strong>in that order<\/strong>, by the time you process a vertex, its current distance is already the <strong>final shortest distance<\/strong>, no need for revisiting like Dijkstra or Bellman-Ford.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"4-32-algorithm-steps\">3.2 Algorithm steps<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Build an adjacency list<\/strong> <code>u \u2192 (v, w)<\/code>.<\/li>\n\n\n\n<li><strong>Topological sort<\/strong> all vertices with a DFS:\n<ul class=\"wp-block-list\">\n<li>Start DFS from every unvisited node.<\/li>\n\n\n\n<li>After finishing a node, push it onto a stack.<\/li>\n\n\n\n<li>When DFS ends, popping the stack yields a valid topo order.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Single-source relaxation<\/strong> in topo order:\n<ul class=\"wp-block-list\">\n<li>Set <code>distance[src] = 0<\/code>, all others to <code>\u221e<\/code>.<\/li>\n\n\n\n<li>Pop vertices one by one.<\/li>\n\n\n\n<li>For each outgoing edge <code>u \u2192 v<\/code> with weight <code>w<\/code>,\n<ul class=\"wp-block-list\">\n<li>if <code>distance[u] + w &lt; distance[v]<\/code>, update <code>distance[v]<\/code>.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Post-process<\/strong> \u2013 convert every <code>\u221e<\/code> to <code>-1<\/code> for unreachable nodes.<\/li>\n<\/ol>\n\n\n\n<p>Because edges only go forward in the order, each one is relaxed <strong>exactly once<\/strong>, giving an <strong>O(V + E) time<\/strong> algorithm, the best you can hope for in a DAG.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"5-4-python-code\">4. Python code<\/h2>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"from typing import List\n\nclass Solution:\n    # ---------- DFS for topological sort ----------\n    def dfs(self, node, stack, visited, adj_list):\n        visited[node] = 1\n        for adjNode, _ in adj_list[node]:         # ignore weight during DFS\n            if visited[adjNode] == 0:\n                self.dfs(adjNode, stack, visited, adj_list)\n        stack.append(node)                        # post-order push\n\n    # ---------- main function ----------\n    def shortestPath(self, V: int, E: int, edges: List[List[int]]) -&gt; List[int]:\n        # 1. Build adjacency list\n        adj_list = [[] for _ in range(V)]\n        for u, v, w in edges:                     # directed edge u -&gt; v (weight w)\n            adj_list[u].append([v, w])\n\n        # 2. Topological sort by DFS\n        stack   = []\n        visited = [0] * V\n        for i in range(V):\n            if visited[i] == 0:\n                self.dfs(i, stack, visited, adj_list)\n\n        # 3. Initialise distance array\n        distance = [float(&quot;inf&quot;)] * V\n        distance[0] = 0                           # source vertex\n\n        # 4. Relax edges following topological order\n        while stack:                              # pop = left-to-right order\n            node = stack.pop()\n            if distance[node] == float(&quot;inf&quot;):    # unreachable so far\n                continue\n            for adjNode, w in adj_list[node]:\n                new_d = distance[node] + w\n                if new_d &lt; distance[adjNode]:\n                    distance[adjNode] = new_d\n\n        # 5. Replace infinity by -1 as problem demands\n        for i in range(V):\n            if distance[i] == float(&quot;inf&quot;):\n                distance[i] = -1\n        return distance\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> typing <\/span><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> List<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">class<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4EC9B0\">Solution<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># ---------- DFS for topological sort ----------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">dfs<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">self<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">node<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">stack<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">visited<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">adj_list<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        visited[node] = <\/span><span style=\"color: #B5CEA8\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> adjNode, _ <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> adj_list[node]:         <\/span><span style=\"color: #6A9955\"># ignore weight during DFS<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> visited[adjNode] == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">self<\/span><span style=\"color: #D4D4D4\">.dfs(adjNode, stack, visited, adj_list)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        stack.append(node)                        <\/span><span style=\"color: #6A9955\"># post-order push<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\"># ---------- main function ----------<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">shortestPath<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">self<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">V<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">E<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">edges<\/span><span style=\"color: #D4D4D4\">: List[List[<\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">]]) -&gt; List[<\/span><span style=\"color: #4EC9B0\">int<\/span><span style=\"color: #D4D4D4\">]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># 1. Build adjacency list<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        adj_list = [[] <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> _ <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V)]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> u, v, w <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> edges:                     <\/span><span style=\"color: #6A9955\"># directed edge u -&gt; v (weight w)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            adj_list[u].append([v, w])<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># 2. Topological sort by DFS<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        stack   = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        visited = [<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">] * V<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> i <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> visited[i] == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #569CD6\">self<\/span><span style=\"color: #D4D4D4\">.dfs(i, stack, visited, adj_list)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># 3. Initialise distance array<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        distance = [<\/span><span style=\"color: #4EC9B0\">float<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;inf&quot;<\/span><span style=\"color: #D4D4D4\">)] * V<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        distance[<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">] = <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">                           <\/span><span style=\"color: #6A9955\"># source vertex<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># 4. Relax edges following topological order<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">while<\/span><span style=\"color: #D4D4D4\"> stack:                              <\/span><span style=\"color: #6A9955\"># pop = left-to-right order<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            node = stack.pop()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> distance[node] == <\/span><span style=\"color: #4EC9B0\">float<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;inf&quot;<\/span><span style=\"color: #D4D4D4\">):    <\/span><span style=\"color: #6A9955\"># unreachable so far<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #C586C0\">continue<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> adjNode, w <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> adj_list[node]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                new_d = distance[node] + w<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> new_d &lt; distance[adjNode]:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    distance[adjNode] = new_d<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\"># 5. Replace infinity by -1 as problem demands<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">for<\/span><span style=\"color: #D4D4D4\"> i <\/span><span style=\"color: #C586C0\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">range<\/span><span style=\"color: #D4D4D4\">(V):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> distance[i] == <\/span><span style=\"color: #4EC9B0\">float<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;inf&quot;<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                distance[i] = -<\/span><span style=\"color: #B5CEA8\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> distance<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"6-5-detailed-step-by-step-explanation\">5. Detailed step-by-step explanation<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Adjacency list<\/strong> \u2013 quickly lists <code>(neighbour, weight)<\/code> pairs for every vertex.<\/li>\n\n\n\n<li><strong><code>dfs<\/code> routine<\/strong> \u2013 a classic post-order push guarantees parents appear <strong>after<\/strong> children in the stack, which reverses to topo order when popped.<\/li>\n\n\n\n<li><strong>Distance array<\/strong> \u2013 <code>\u221e<\/code> (here <code>float('inf')<\/code>) means \u201cnot reached yet\u201d.<\/li>\n\n\n\n<li><strong>Relaxation loop<\/strong>\n<ul class=\"wp-block-list\">\n<li>If the current node is still at <code>\u221e<\/code>, no shorter path can arise later because no incoming edges remain, so we skip it.<\/li>\n\n\n\n<li>Otherwise explore its outgoing edges and update neighbours if we find a cheaper route.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Final loop<\/strong> converts unreached vertices to <code>-1<\/code> per the spec.<\/li>\n<\/ol>\n\n\n\n<p>Because each vertex and edge is touched only once across DFS + relaxation, the algorithm is linear.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"7-6-dry-run-on-the-sample-graph\">6. Dry run on the sample graph<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Stack build (push order)<\/th><th>Stack after DFS<\/th><th>Pop order (topo)<\/th><\/tr><\/thead><tbody><tr><td>5, 4, 2, 1, 3, 0 (example)<\/td><td><code>[5,4,2,1,3,0]<\/code><\/td><td>0 \u2192 3 \u2192 1 \u2192 2 \u2192 4 \u2192 5<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Relaxation in that pop order produces the distances <code>0 2 3 6 1 5<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"8-7-complexity-analysis\">7. Complexity analysis<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Metric<\/th><th>Cost<\/th><th>Why<\/th><\/tr><\/thead><tbody><tr><td><strong>Time<\/strong><\/td><td><strong>O(V + E)<\/strong><\/td><td>DFS visits each vertex\/edge once; relaxation does the same<\/td><\/tr><tr><td><strong>Space<\/strong><\/td><td><strong>O(V + E)<\/strong><\/td><td>Adjacency list + call stack + <code>distance<\/code> + <code>visited<\/code> arrays<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"9-8conclusion\">8.Conclusion<\/h2>\n\n\n\n<p>When the graph is a <strong>weighted DAG<\/strong>, the combination of <strong>topological sorting<\/strong> plus <strong>single-pass edge relaxation<\/strong> gives the fastest and simplest single-source shortest-path algorithm:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Linear time<\/strong> \u2013 beats Dijkstra (needs a heap) and Bellman-Ford (multi-pass).<\/li>\n\n\n\n<li><strong>In-place friendly<\/strong> \u2013 only a handful of arrays, no exotic data structures.<\/li>\n\n\n\n<li><strong>Conceptually clear<\/strong> \u2013 once you trust topological order, relaxation is guaranteed to be final.<\/li>\n<\/ul>\n\n\n\n<p>Next time you see a DAG with weights, reach straight for this technique!<\/p>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/www.codeanddebug.in\/course\/zero-to-hero-python-dsa\">Join our Advance DSA COURSE<\/a><\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><em>For any changes to the article, kindly email at <a href=\"mailto:code@codeanddebug.in\">code@codeanddebug.in<\/a> or contact us at <a href=\"tel:+91-9712928220\">+91-9712928220<\/a>.<\/em><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to find single source shortest path in a weighted directed acyclic graph (DAG) in linear time. We explain topological sorting by DFS, step-by-step edge relaxation, include fully-commented Python code, a hand dry-run, and clear Big-O analysis. Here&#8217;s the [Problem Link] to begin with. 1. What does the problem ask? Given return an array<\/p>\n","protected":false},"author":1,"featured_media":321,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,6],"tags":[20,17,23],"class_list":{"0":"post-319","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-data-structures-and-algorithm","8":"category-intermediate","9":"tag-dfs","10":"tag-graph","11":"tag-shortest-path"},"featured_image_src":"https:\/\/codeanddebug.in\/blog\/wp-content\/uploads\/2025\/06\/shortest-path-in-directed-acyclic-graph-featured-image.png","author_info":{"display_name":"codeanddebug","author_link":"https:\/\/codeanddebug.in\/blog\/author\/codeanddebug\/"},"_links":{"self":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/319","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/comments?post=319"}],"version-history":[{"count":3,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/319\/revisions"}],"predecessor-version":[{"id":330,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/posts\/319\/revisions\/330"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media\/321"}],"wp:attachment":[{"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/media?parent=319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/categories?post=319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codeanddebug.in\/blog\/wp-json\/wp\/v2\/tags?post=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}