Last Updated: April 2, 2026
We have a weighted undirected graph and need to find two things: the shortest path distance from node 0 to node n-1, and the number of distinct shortest paths that achieve that distance.
This is a classic extension of Dijkstra's algorithm. Standard Dijkstra finds the shortest distance, but here we also need to count how many different paths produce that same shortest distance. The trick is to maintain a count array alongside the distance array. When we find a shorter path to a node, we reset its count. When we find another path with the same shortest distance, we add to the count.
The key observation: whenever Dijkstra relaxes an edge and finds a new shortest distance to some node, we know the count of shortest paths to that node is exactly the count of the node we came from. And if we find an equally short path through a different node, we add that node's count to the running total.
1 <= n <= 200 → The graph has at most 200 nodes. This is small enough for O(n^2) or O(n^2 log n) approaches. Even Floyd-Warshall at O(n^3) would be 8 million operations, perfectly fine.n - 1 <= roads.length <= n * (n - 1) / 2 → The graph is connected (at least n-1 edges) and can be dense (up to ~20,000 edges for n=200).1 <= time_i <= 10^9 → Edge weights can be very large, so the total shortest path distance can exceed the int range. We need long/64-bit integers for distance tracking.modulo 10^9 + 7 → The number of paths can be astronomically large, so we take the count modulo a prime.The most direct approach: find all possible paths from node 0 to node n-1, compute each path's total weight, find the minimum weight among all paths, and count how many paths have that minimum weight.
We can enumerate paths using DFS. Starting from node 0, we explore every possible route to node n-1, tracking the accumulated distance. After exploring all paths, we know the shortest distance and can count how many paths match it.
This is correct but wildly inefficient. The number of simple paths in a graph can be exponential (factorial in the worst case for dense graphs). With n up to 200, this is completely impractical.
We are enumerating every possible path, which is exponentially slow. Many subpaths are shared between routes but get recomputed. What if we computed the shortest distance to each node just once and counted the shortest paths incrementally?
Here is the core insight: Dijkstra's algorithm already processes nodes in order of their shortest distance from the source. When we pop a node from the priority queue, we know its final shortest distance. So we can piggyback a counting mechanism on top of Dijkstra.
We maintain two arrays: dist[i] for the shortest distance from node 0 to node i, and ways[i] for the number of shortest paths from node 0 to node i. Initially, dist[0] = 0 and ways[0] = 1 (there is exactly one way to be at the start: you are already there).
When we relax an edge from node u to node v with weight w, three things can happen:
dist[u] + w < dist[v]. We update dist[v] and set ways[v] = ways[u], because all previous paths to v are no longer shortest, and the only shortest paths to v now come through u.dist[u] + w == dist[v]. We add ways[u] to ways[v], because we discovered additional shortest paths that go through u.dist[u] + w > dist[v]. We ignore it completely.Dijkstra's algorithm processes nodes in order of increasing distance. When node u is popped from the heap, dist[u] is finalized, and so is ways[u]. Every shortest path to u has already been discovered, because any path through an unprocessed node would have a distance at least as large as dist[u].
So when we relax edges from u, we can safely use ways[u] as the final count. If we discover a new shortest path to v (shorter than what we had before), we know the only way to achieve that distance is through u, so ways[v] = ways[u]. If the distance matches, we know there are additional shortest paths through u, so we add ways[u] to the existing count.
dist array with infinity and ways array with 0. Set dist[0] = 0 and ways[0] = 1.(0, 0) (distance, node) into a min-heap. a. Pop the node with the smallest distance. Call it (d, u).
b. If d > dist[u], skip (stale entry).
c. For each neighbor v with edge weight w:
dist[u] + w < dist[v]: update dist[v] = dist[u] + w, set ways[v] = ways[u], push to heap.dist[u] + w == dist[v]: add ways[u] to ways[v] (modulo 10^9+7).ways[n-1].