Number of Ways to Reach Destination in Shortest Time (original) (raw)
Last Updated : 18 Nov, 2025
Given an undirected weighted graph containing **V vertices from **0 to V-1 represented as an adjacency list **adj[][], where each adj[u] contains pairs [v, t] indicating there is an edge between nodes u and v such that it takes travel time of t to reach from u to v or v to u.
Find the number of distinct paths to reach(V-1)th node from 0th node in **minimum amount of time.
**Examples:
**Input: adj[][] = [[[1, 2], [3, 5]],
[0, 2], [2, 3], [3, 3]],
[1, 3], [3, 4]],
[0, 5], [1, 3], [2, 4]]]
**Output: 2
**Explanation: The shortest path from 0 to 3 exists via 2 paths 0 -> 3 and 0 -> 1 -> 3 each having a cost of 5.**Input: adj[][] =[[[2, 3], [4, 2], [5, 7]],
[[4, 1], [5, 4]],
[[0, 3], [3, 1], [5, 5]],
[[2, 1], [5, 3]],
[[0, 2], [1, 1], [5, 5]],
[[0, 7], [1, 4], [2, 5], [3, 3], [4, 5]]]
**Output: 4
**Explanation: The shortest paths from 0 to 5 are-
0 -> 5 (7)
0 -> 4 -> 5 (2+ 5 = 7)
0 -> 4 -> 1 -> 5 (2 + 1 + 4 = 7)
0 -> 2 -> 3 -> 5 (3 + 1 + 3 = 7)
Table of Content
- [Naive Approach] By pruned DFS
- [Expected Approach] Using Dijkstra's Algorithm - O(V+ E log E) Time and O(V+E) Space
[Naive Approach] By pruned DFS
We start a DFS from node 0 and explore every possible path to the destination n-1. While exploring, we track the total time taken so far. If at any point this time exceeds the current best (shortest) time, we stop exploring that path because we already know a faster route exists through some other path. If we reach the destination, we check whether this path is faster than all previous ones; if it is, we update the shortest time and reset the count of ways to 1. If it matches the current shortest time, we simply increase the count.
During DFS, we mark nodes as visited to avoid revisiting them in the same path, and unmark them on backtracking so other paths can reuse the node. In this way, we systematically try all valid paths, prune the ones that are guaranteed to be worse, and finally count how many distinct paths achieve the minimum possible time.
C++ `
//Driver Code Starts #include #include #include using namespace std;
//Driver Code Ends
void dfs(int node, int currentTime, vector<vector<pair<int,int>>>& adj, vector& vis, int V, int& shortest, int& ways) {
// prune: no need to go further
if (currentTime > shortest) return;
if (node == V - 1) {
// if time to reach the node is new minimum
// change the number of ways to 1(for current path)
if (currentTime < shortest) {
shortest = currentTime;
ways = 1;
}
// increment the number of ways to
// reach the node in shortest time
else if (currentTime == shortest) {
ways++;
}
return;
}
vis[node] = 1;
for (auto &p : adj[node]) {
int next = p.first;
int wt = p.second;
if (vis[next] == 0) {
dfs(next, currentTime + wt, adj, vis, V, shortest, ways);
}
}
// backtracking and marking
// node as unvisited
vis[node] = 0;}
int countPaths(vector<vector<pair<int,int>>>& adj) { int V = adj.size(); vector vis(V, 0);
// to store the shortest time
// needed to reach node V-1 from 0
int shortest = INT_MAX;
// number of ways to reach
// node V-1 in shortest time
int ways = 0;
dfs(0, 0, adj, vis, V, shortest, ways);
return ways;}
//Driver Code Starts
void addEdge(vector<vector<pair<int,int>>>& adj, int u, int v, int wt) { adj[u].push_back({v, wt}); adj[v].push_back({u, wt}); }
int main() { int V = 4; vector<vector<pair<int,int>>> adj(V);
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
cout << countPaths(adj);}
//Driver Code Ends
Java
//Driver Code Starts import java.util.ArrayList; import java.util.Arrays;
class GFG {
//Driver Code Ends
static void dfs(int node, int currentTime, ArrayList<ArrayList<int[]>> adj,
int[] vis, int V, int[] shortest, int[] ways) {
// prune: no need to go further
if (currentTime > shortest[0]) return;
if (node == V - 1) {
// if time to reach the node is new minimum
// change the number of ways to 1(for current path)
if (currentTime < shortest[0]) {
shortest[0] = currentTime;
ways[0] = 1;
}
// increment the number of ways to
// reach the node in shortest time
else if (currentTime == shortest[0]) {
ways[0]++;
}
return;
}
vis[node] = 1;
for (int[] p : adj.get(node)) {
int next = p[0];
int wt = p[1];
if (vis[next] == 0) {
dfs(next, currentTime + wt, adj, vis, V, shortest, ways);
}
}
// backtracking and marking
// node as unvisited
vis[node] = 0;
}
static int countPaths(ArrayList<ArrayList<int[]>> adj) {
int V = adj.size();
int[] vis = new int[V];
// to store the shortest time
// needed to reach node V-1 from 0
int[] shortest = new int[]{Integer.MAX_VALUE};
// number of ways to reach
// node V-1 in shortest time
int[] ways = new int[]{0};
dfs(0, 0, adj, vis, V, shortest, ways);
return ways[0];
}//Driver Code Starts
static void addEdge(ArrayList<ArrayList<int[]>> adj, int u, int v, int wt) {
adj.get(u).add(new int[]{v, wt});
adj.get(v).add(new int[]{u, wt});
}
public static void main(String[] args) {
int V = 4;
ArrayList<ArrayList<int[]>> adj = new ArrayList<>();
for (int i = 0; i < V; i++) adj.add(new ArrayList<>());
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
System.out.println(countPaths(adj));
}}
//Driver Code Ends
Python
def dfs(node, currentTime, adj, vis, V, shortest, ways):
# prune: no need to go further
if currentTime > shortest[0]:
return
if node == V - 1:
# if time to reach the node is new minimum
# change the number of ways to 1(for current path)
if currentTime < shortest[0]:
shortest[0] = currentTime
ways[0] = 1
# increment the number of ways to
# reach the node in shortest time
elif currentTime == shortest[0]:
ways[0] += 1
return
vis[node] = 1
for p in adj[node]:
next = p[0]
wt = p[1]
if vis[next] == 0:
dfs(next, currentTime + wt, adj, vis, V, shortest, ways)
# backtracking and marking
# node as unvisited
vis[node] = 0def countPaths(adj): V = len(adj) vis = [0] * V
# to store the shortest time
# needed to reach node V-1 from 0
shortest = [10**18]
# number of ways to reach
# node V-1 in shortest time
ways = [0]
dfs(0, 0, adj, vis, V, shortest, ways)
return ways[0]#Driver Code Starts def addEdge(adj, u, v, wt): adj[u].append((v, wt)) adj[v].append((u, wt))
if name == "main": V = 4 adj = [[] for _ in range(V)]
addEdge(adj, 0, 1, 2)
addEdge(adj, 0, 3, 5)
addEdge(adj, 1, 2, 3)
addEdge(adj, 1, 3, 3)
addEdge(adj, 2, 3, 4)
print(countPaths(adj))#Driver Code Ends
C#
//Driver Code Starts using System; using System.Collections.Generic;
class GFG { //Driver Code Ends
static void dfs(int node, int currentTime, List<List<int[]>> adj,
int[] vis, int V, int[] shortest, int[] ways) {
// prune: no need to go further
if (currentTime > shortest[0]) return;
if (node == V - 1) {
// if time to reach the node is new minimum
// change the number of ways to 1(for current path)
if (currentTime < shortest[0]) {
shortest[0] = currentTime;
ways[0] = 1;
}
// increment the number of ways to
// reach the node in shortest time
else if (currentTime == shortest[0]) {
ways[0]++;
}
return;
}
vis[node] = 1;
foreach (var p in adj[node]) {
int next = p[0];
int wt = p[1];
if (vis[next] == 0)
{
dfs(next, currentTime + wt, adj, vis, V, shortest, ways);
}
}
// backtracking and marking
// node as unvisited
vis[node] = 0;
}
static int countPaths(List<List<int[]>> adj) {
int V = adj.Count;
int[] vis = new int[V];
// to store the shortest time
// needed to reach node V-1 from 0
int[] shortest = new int[] { int.MaxValue };
// number of ways to reach
// node V-1 in shortest time
int[] ways = new int[] { 0 };
dfs(0, 0, adj, vis, V, shortest, ways);
return ways[0];
}//Driver Code Starts
static void addEdge(List<List<int[]>> adj, int u, int v, int wt) {
adj[u].Add(new int[] { v, wt });
adj[v].Add(new int[] { u, wt });
}
static void Main() {
int V = 4;
var adj = new List<List<int[]>>();
for (int i = 0; i < V; i++) adj.Add(new List<int[]>());
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
Console.WriteLine(countPaths(adj));
}}
//Driver Code Ends
JavaScript
function dfs(node, currentTime, adj, vis, V, shortest, ways) {
// prune: no need to go further
if (currentTime > shortest[0]) return;
if (node === V - 1) {
// if time to reach the node is new minimum
// change the number of ways to 1(for current path)
if (currentTime < shortest[0]) {
shortest[0] = currentTime;
ways[0] = 1;
}
// increment the number of ways to
// reach the node in shortest time
else if (currentTime === shortest[0]) {
ways[0]++;
}
return;
}
vis[node] = 1;
for (let p of adj[node]) {
let next = p[0];
let wt = p[1];
if (vis[next] === 0) {
dfs(next, currentTime + wt, adj, vis, V, shortest, ways);
}
}
// backtracking and marking
// node as unvisited
vis[node] = 0;}
function countPaths(adj) { let V = adj.length; let vis = Array(V).fill(0);
// to store the shortest time
// needed to reach node V-1 from 0
let shortest = [Number.MAX_SAFE_INTEGER];
// number of ways to reach
// node V-1 in shortest time
let ways = [0];
dfs(0, 0, adj, vis, V, shortest, ways);
return ways[0];}
//Driver Code Starts function addEdge(adj, u, v, wt) { adj[u].push([v, wt]); adj[v].push([u, wt]); }
// Driver code let V = 4; let adj = Array.from({ length: V }, () => []);
addEdge(adj, 0, 1, 2); addEdge(adj, 0, 3, 5); addEdge(adj, 1, 2, 3); addEdge(adj, 1, 3, 3); addEdge(adj, 2, 3, 4);
console.log(countPaths(adj)); //Driver Code Ends
`
**Time Complexity: O(KV), where K is the average branching factor of the vertices in the graph and V is the number of vertices in the graph.
**Space Complexity: O(V) where V is the number of vertices in the graph.
[Expected Approach] Using Dijkstra's Algorithm - O(V+ E log E) Time and O(V+E) Space
Since, we need to find distinct shortest paths from source to destination and the graph contains positive edge weights, we can use dijkstra's algorithm. Here, we use Dijkstra’s algorithm to track both the shortest time to each node and the number of ways to reach that node in minimum time. We maintain a minTime[] array for the best time to reach each node and a paths[] array for how many shortest paths lead there. As we relax edges, if we find a strictly better time, we update both the time and the path count. If we find an equal time, we add the number of paths from the current node. By the end, paths[V-1] gives the total number of shortest paths to the destination.
C++ `
//Driver Code Starts #include #include #include #include using namespace std;
//Driver Code Ends
int countPaths(vector<vector<pair<int, int>>>& adj) { int V = adj.size();
// min time to reach a node from src(0)
vector<int> minTime(V, INT_MAX);
// number of ways to reach a node
// from src(0) with minimum cost
vector<int> paths(V, 0);
minTime[0] = 0;
paths[0] = 1;
// sort nodes by time taken to reach
// them from src in ascending order
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
pq.push({0, 0});
while (!pq.empty()) {
auto top = pq.top(); pq.pop();
int node = top.second;
int currentTime = top.first;
if (currentTime > minTime[node]) continue;
for (auto& next : adj[node]) {
int nextNode = next.first;
int nextTime = next.second;
int newTime = nextTime + currentTime;
// if newTime is less than stored value
// then update paths and time
if (newTime < minTime[nextNode]) {
minTime[nextNode] = newTime;
paths[nextNode] = paths[node];
pq.push({newTime, nextNode});
} else if (newTime == minTime[nextNode]) {
// increment the count of
// paths if time is same
paths[nextNode] = (paths[nextNode] + paths[node]);
}
}
}
// return number of paths to reach
// dest from src in min time
return paths[V - 1];}
//Driver Code Starts
void addEdge(vector<vector<pair<int,int>>>& adj, int u, int v, int wt) { adj[u].push_back({v, wt}); adj[v].push_back({u, wt}); }
int main() { int V = 4; vector<vector<pair<int, int>>> adj(V);
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
cout << countPaths(adj);} //Driver Code Ends
Java
//Driver Code Starts import java.util.ArrayList; import java.util.Arrays; import java.util.PriorityQueue;
class GFG { //Driver Code Ends
static int countPaths(ArrayList<ArrayList<int[]>> adj) {
int V = adj.size();
// min time to reach a node from src(0)
int[] minTime = new int[V];
// number of ways to reach a node
// from src(0) with minimum cost
int[] paths = new int[V];
Arrays.fill(minTime, Integer.MAX_VALUE);
minTime[0] = 0;
paths[0] = 1;
// sort nodes by time taken to reach
// them from src in ascending order
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
pq.offer(new int[]{0, 0});
while (!pq.isEmpty()) {
int[] top = pq.poll();
int node = (int) top[1];
int currentTime = top[0];
if (currentTime > minTime[node]) continue;
for (int[] next : adj.get(node)) {
int nextNode = (int) next[0];
int nextTime = next[1];
int newTime = nextTime + currentTime;
// if newTime is less than stored value
// then update paths and time
if (newTime < minTime[nextNode]) {
minTime[nextNode] = newTime;
paths[nextNode] = paths[node];
pq.offer(new int[]{newTime, nextNode});
} else if (newTime == minTime[nextNode]) {
// increment the count of
// paths if time is same
paths[nextNode] = (paths[nextNode] + paths[node]);
}
}
}
// return number of paths to reach
// dest from src in min time
return paths[V - 1];
}//Driver Code Starts static void addEdge(ArrayList<ArrayList<int[]>> adj, int u, int v, int wt) { // directed graph adj.get(u).add(new int[]{v, wt}); adj.get(v).add(new int[]{u, wt}); }
public static void main(String[] args) {
int V = 4;
ArrayList<ArrayList<int[]>> adj = new ArrayList<>();
for (int i = 0; i < V; i++) {
adj.add(new ArrayList<>());
}
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
System.out.println(countPaths(adj));
}} //Driver Code Ends
Python
#Driver Code Starts import heapq
#Driver Code Ends
def countPaths(adj): V = len(adj) # min time to reach a node from src(0) minTime = [float('inf')] * V
# number of ways to reach a node
# from src(0) with minimum cost
paths = [0] * V
minTime[0] = 0
paths[0] = 1
# sort nodes by time taken to reach
# them from src in ascending order
pq = [(0, 0)] # (time, node)
while pq:
currentTime, node = heapq.heappop(pq)
if currentTime > minTime[node]:
continue
for nextNode, nextTime in adj[node]:
newTime = nextTime + currentTime
# if newTime is less than stored value
# then update paths and time
if newTime < minTime[nextNode]:
minTime[nextNode] = newTime
paths[nextNode] = paths[node]
heapq.heappush(pq, (newTime, nextNode))
elif newTime == minTime[nextNode]:
# increment the count of
# paths if time is same
paths[nextNode] = (paths[nextNode] + paths[node])
# return number of paths to reach
# dest from src in min time
return paths[V - 1]#Driver Code Starts
def addEdge(adj, u, v, wt): adj[u].append((v, wt)) adj[v].append((u, wt))
if name == "main": V = 4 adj = [[] for _ in range(V)]
addEdge(adj, 0, 1, 2)
addEdge(adj, 0, 3, 5)
addEdge(adj, 1, 2, 3)
addEdge(adj, 1, 3, 3)
addEdge(adj, 2, 3, 4)
print(countPaths(adj))#Driver Code Ends
C#
//Driver Code Starts using System; using System.Collections.Generic;
class GFG { //Driver Code Ends
static int countPaths(List<List<int[]>> adj) {
int V = adj.Count;
// min time to reach a node from src(0)
int[] minTime = new int[V];
// number of ways to reach a node
// from src(0) with minimum cost
int[] paths = new int[V];
for (int i = 0; i < V; i++) minTime[i] = int.MaxValue;
minTime[0] = 0;
paths[0] = 1;
// sort nodes by time taken to reach
// them from src in ascending order
var pq = new SortedSet<Tuple<int, int>>(
Comparer<Tuple<int, int>>.Create((a, b) =>
a.Item1 != b.Item1 ? a.Item1 - b.Item1 : a.Item2 - b.Item2
)
);
pq.Add(Tuple.Create(0, 0));
while (pq.Count > 0) {
var top = pq.Min;
pq.Remove(top);
int node = top.Item2;
int currentTime = top.Item1;
if (currentTime > minTime[node]) continue;
foreach (var next in adj[node]) {
int nextNode = next[0];
int nextTime = next[1];
int newTime = nextTime + currentTime;
// if newTime is less than stored value
// then update paths and time
if (newTime < minTime[nextNode]) {
minTime[nextNode] = newTime;
paths[nextNode] = paths[node];
pq.Add(Tuple.Create(newTime, nextNode));
} else if (newTime == minTime[nextNode]) {
// increment the count of
// paths if time is same
paths[nextNode] = (paths[nextNode] + paths[node]) ;
}
}
}
// return number of paths to reach
// dest from src in min time
return paths[V - 1];
}//Driver Code Starts
static void addEdge(List<List<int[]>> adj, int u, int v, int wt) {
adj[u].Add(new int[] { v, wt });
adj[v].Add(new int[] { u, wt });
}
static void Main() {
int V = 4;
var adj = new List<List<int[]>>();
for (int i = 0; i < V; i++)
adj.Add(new List<int[]>());
addEdge(adj, 0, 1, 2);
addEdge(adj, 0, 3, 5);
addEdge(adj, 1, 2, 3);
addEdge(adj, 1, 3, 3);
addEdge(adj, 2, 3, 4);
Console.WriteLine(countPaths(adj));
}} //Driver Code Ends
JavaScript
function countPaths(adj) { let V = adj.length;
// min time to reach a node from src(0)
let minTime = Array(V).fill(Number.MAX_SAFE_INTEGER);
// number of ways to reach a node
// from src(0) with minimum cost
let paths = Array(V).fill(0);
minTime[0] = 0;
paths[0] = 1;
// sort nodes by time taken to reach
// them from src in ascending order
let pq = [[0, 0]]; // [node, time]
while (pq.length) {
pq.sort((a, b) => a[0] - b[0]);
let [currentTime, node] = pq.shift();
if (currentTime > minTime[node]) continue;
for (let [nextNode, nextTime] of adj[node]) {
let newTime = nextTime + currentTime;
// if newTime is less than stored value
// then update paths and time
if (newTime < minTime[nextNode]) {
minTime[nextNode] = newTime;
paths[nextNode] = paths[node];
pq.push([newTime, nextNode]);
} else if (newTime === minTime[nextNode]) {
// increment the count of
// paths if time is same
paths[nextNode] = (paths[nextNode] + paths[node]);
}
}
}
// return number of paths to reach
// dest from src in min time
return paths[V - 1];}
//Driver Code Starts function addEdge(adj, u, v, wt) { adj[u].push([v, wt]); adj[v].push([u, wt]); }
// Driver code let V = 4; let adj = Array.from({ length: V}, () => []);
addEdge(adj, 0, 1, 2); addEdge(adj, 0, 3, 5); addEdge(adj, 1, 2, 3); addEdge(adj, 1, 3, 3); addEdge(adj, 2, 3, 4);
console.log(countPaths(adj)); //Driver Code Ends
`

