package main import ( "fmt" "math" ) type Edge struct { to, weight int } func shortestPathDAG(n int, edges [][]Edge, start int) []int { dist := make([]int, n) for i := range dist { dist[i] = math.MaxInt64 } dist[start] = 0 visited := make([]bool, n) var stack []int var dfs func(int) dfs = func(u int) { visited[u] = true for _, e := range edges[u] { if !visited[e.to] { dfs(e.to) } } stack = append(stack, u) } for i := 0; i < n; i++ { if !visited[i] { dfs(i) } } for i := len(stack) - 1; i >= 0; i-- { u := stack[i] if dist[u] != math.MaxInt64 { for _, e := range edges[u] { if dist[u]+e.weight < dist[e.to] { dist[e.to] = dist[u] + e.weight } } } } return dist } func main() { n := 6 edges := make([][]Edge, n) edges[0] = []Edge{{1, 5}, {2, 3}} edges[1] = []Edge{{3, 6}, {2, 2}} edges[2] = []Edge{{4, 2}, {5, 0}, {3, 3}} edges[3] = []Edge{{4, -1}, {5, 1}} edges[4] = []Edge{{5, -2}} start := 1 dist := shortestPathDAG(n, edges, start) fmt.Println(dist) }
The code performs a topological sort using DFS, then relaxes edges in topological order to find shortest paths from node 1.
Starting from node 1 with distance 0, the distances to reachable nodes update as follows:
- Node 2: 2 (via edge 1->2 with weight 2)
- Node 3: 5 (via 1->2->3 with weights 2+3)
- Node 4: 4 (via 1->2->4 with weights 2+2)
- Node 5: 2 (via 1->2->5 with weights 2+0 or 1->2->4->5 with weights 2+2+(-2))
Nodes unreachable from start remain at MaxInt64 (9223372036854775807).
Topological order processes nodes so that all edges go from earlier to later nodes. This means when we relax edges, all predecessors of a node have their shortest distances computed already, ensuring correct updates without revisiting nodes.
for i := len(stack) - 1; i >= 0; i-- { u := stack[i] if dist[u] != math.MaxInt64 { for _, e := range edges[u] { if dist[u]+e.weight <= dist[e.to] { dist[e.to] = dist[u] + e.weight } } } }
The use of '<=' allows updating distances even when the new distance equals the current one, causing redundant updates and possibly incorrect paths.
Using '<' ensures updates only when a strictly shorter path is found.
var dfs func(int) dfs = func(u int) { visited[u] = true for _, e := range edges[u] { if !visited[e.to] { dfs(e.to) } } stack = append(stack, u) }
The code correctly declares a variable dfs of function type and assigns an anonymous function to it. The braces are balanced and syntax is valid.
From node 0, all nodes 1, 2, 3, 4, 5 are reachable through paths:
- 0->1
- 0->2
- 0->1->3
- 0->2->4
- 0->1->3->5
- 0->2->4->3
All 6 nodes (0 to 5) have finite shortest distances.
