Number of Ways to Reach Destination in Shortest Time

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]]]

1

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]]]

2

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)

Try It Yourself
redirect icon

[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 <iostream>
#include <vector>
#include <climits>
using namespace std;


//Driver Code Ends

void dfs(int node, int currentTime, vector<vector<pair<int,int>>>& adj,
         vector<int>& 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<int> 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] = 0


def 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

Output
2

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 <iostream>
#include <vector>
#include <queue>
#include <climits>
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

Output
2
Comment