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

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 Yourselfredirect icon

Table of Content

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

`

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

`