Given an undirected graph with N nodes (numbered from 0 to N-1) such that any node can be reached from any other node and there are no parallel edges. Also, an integer array edges[] is given where each element is of the form {u, v, t} which represents an edge between u and v and it takes t time to move on the edge. The task is to find the number of ways to reach from node 0 to node N-1 in minimum time.
Examples:
Input: N = 7, M = 10, edges = [[0, 6, 7], [0, 1, 2], [1, 2, 3], [1, 3, 3], [6, 3, 3], [3, 5, 1], [6, 5, 1], [2, 5, 1], [0, 4, 5], [4, 6, 2]]
Output: 4
Explanation: The four ways to get there in 7 minutes are:
0->6
0->4->6
0->1->2->5->6
0->1->3->5->6Input: N = 6, M = 8, edges = [[0, 5, 8], [0, 2, 2], [0, 1, 1], [1, 3, 3], [1, 2, 3], [2, 5, 6], [3, 4, 2], [4, 5, 2]]
Output: 3
Explanation: The three ways to get there in 8 minutes are:
0->5
0->2->5
0->1->3->4->5
Naive Approach: The problem can be solved using Dijkstra's Algorithm based on the below idea:
For each node we can store the minimum time taken to reach from 0 and number of ways to reach the node. Say we keep an array time[], where time[i] denotes the minimum time to travel from 0th node to ith node and another array ways[], where ways[i] denotes the number of way we can reach ith node from 0th node in minimum time. Consider time_taken(u, v) denotes time taken to go to v from u. Now there are two cases:
- If (time[u] + time_taken(u, v) < time[v]) , then ways[v] = ways[u]
- If (time[u] + time_taken(u, v) == time[v]), then ways[v] = ways[v] + ways[u]
Follow the below steps to solve the problem:
- First, we make an adjacency matrix from the roads array
- Adjacency matrix is 2D matrix adj of size (V*V)
- adj[u][v] stores the time it takes to go from u to
- time[0] = 0 and ways[0] = 1
- Now we start from 0 node and start the Dijkstra algorithm
- We find the node with minimum time to travel which is not visited yet, let's take the node as a.
- Run a loop through all the nodes which are not visited and keep track of the node with the smallest time to travel.
- Then minimize the time of nodes that are adjacent to a:
- we run a loop through all the nodes if there is a connection between a node and we check the following two conditions
- If (time[u]+time_taken(u, v) < time[v]) , then ways[v] = ways[u]
- If (time[u] + time_taken(u, v) == time[v]), then ways[v] = ways[v] + ways[u]
- We find the node with minimum time to travel which is not visited yet, let's take the node as a.
Below is the implementation of the above approach:
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
// Function to get the minimum position
int getmin(vector<long long int>& dist,
vector<bool>& visited, int n)
{
long long int x = LLONG_MAX, pos;
for (int i = 0; i < n; i++) {
if (!visited[i] && dist[i] < x) {
x = dist[i];
pos = i;
}
}
return pos;
}
// Function to count number of paths
int countPaths(int n, vector<vector<int> >& roads)
{
int mod = 1e9 + 7;
long long int MMAX = 1e17;
vector<vector<int> > adj(n, vector<int>(n, 0));
for (auto road : roads) {
int u = road[0];
int v = road[1];
int t = road[2];
adj[u][v] = t;
adj[v][u] = t;
}
vector<bool> visited(n, false);
vector<long long int> time(n, MMAX);
vector<long long int> ways(n, 0);
time[0] = 0;
ways[0] = 1;
for (int i = 0; i < n - 1; i++) {
// Find the intersection with minimum
// time to travel
int u = getmin(time, visited, n);
visited[u] = true;
for (int v = 0; v < n; v++) {
if (!visited[v] && adj[u][v]
&& time[u] != MMAX) {
if (time[u] + adj[u][v] < time[v]) {
time[v] = time[u] + adj[u][v];
ways[v] = ways[u];
}
else if (time[u] + adj[u][v] == time[v]) {
ways[v] = ways[v] + ways[u];
ways[v] %= mod;
}
}
}
}
return ways[n - 1];
}
// Driver Code
int main()
{
int N = 7, M = 10;
vector<vector<int> > edges
= { { 0, 6, 7 }, { 0, 1, 2 }, { 1, 2, 3 }, { 1, 3, 3 }, { 6, 3, 3 }, { 3, 5, 1 }, { 6, 5, 1 }, { 2, 5, 1 }, { 0, 4, 5 }, { 4, 6, 2 } };
// Function Call
cout << countPaths(N, edges) << endl;
return 0;
}
// Java code to implement the approach
import java.io.*;
import java.util.*;
public class Main {
// Function to get the minimum position
static int getmin(long[] dist, boolean[] visited, int n)
{
long x = Long.MAX_VALUE;
int pos = 0;
for (int i = 0; i < n; i++) {
if (!visited[i] && dist[i] < x) {
x = dist[i];
pos = i;
}
}
return pos;
}
// Function to count number of paths
static int countPaths(int n, List<List<Integer> > roads)
{
int mod = (int)1e7;
int MMAX = (int)1e17;
int[][] adj = new int[n][n];
for (List<Integer> road : roads) {
int u = road.get(0);
int v = road.get(1);
int t = road.get(2);
adj[u][v] = t;
adj[v][u] = t;
}
boolean[] visited = new boolean[n];
long[] time = new long[n];
Arrays.fill(time, MMAX);
long[] ways = new long[n];
time[0] = 0;
ways[0] = 1;
for (int i = 0; i < n - 1; i++) {
// Find the intersection with minimum
// time to travel
int u = getmin(time, visited, n);
visited[u] = true;
for (int v = 0; v < n; v++) {
if (!visited[v] && adj[u][v]!=0
&& time[u] != MMAX) {
if (time[u] + adj[u][v] < time[v]) {
time[v] = time[u] + adj[u][v];
ways[v] = ways[u];
}
else if (time[u] + adj[u][v]
== time[v]) {
ways[v] = ways[v] + ways[u];
ways[v] %= mod;
}
}
}
}
return (int)ways[n - 1];
}
public static void main(String[] args)
{
int N = 7, M = 10;
List<List<Integer> > edges = new ArrayList<>();
edges.add(Arrays.asList(0, 6, 7));
edges.add(Arrays.asList(0, 1, 2));
edges.add(Arrays.asList(1, 2, 3));
edges.add(Arrays.asList(1, 3, 3));
edges.add(Arrays.asList(6, 3, 3));
edges.add(Arrays.asList(3, 5, 1));
edges.add(Arrays.asList(6, 5, 1));
edges.add(Arrays.asList(2, 5, 1));
edges.add(Arrays.asList(0, 4, 5));
edges.add(Arrays.asList(4, 6, 2));
// Function Call
System.out.println(countPaths(N, edges));
}
}
// This code is contributed by lokesh
# Python implementation
import sys
# Function to get the minimum position
def getmin(dist, visited, n):
x = sys.maxsize
pos = -1
for i in range(n):
if not visited[i] and dist[i] < x:
x = dist[i]
pos = i
return pos
# Function to count number of paths
def countPaths(n, roads):
mod = 10**9 + 7
MMAX = 10**17
adj = [[0] * n for _ in range(n)]
for road in roads:
u, v, t = road[0], road[1], road[2]
adj[u][v] = t
adj[v][u] = t
visited = [False] * n
time = [MMAX] * n
ways = [0] * n
time[0] = 0
ways[0] = 1
for i in range(n - 1):
# Find the intersection with minimum
# time to travel
u = getmin(time, visited, n)
visited[u] = True
for v in range(n):
if not visited[v] and adj[u][v] and time[u] != MMAX:
if time[u] + adj[u][v] < time[v]:
time[v] = time[u] + adj[u][v]
ways[v] = ways[u]
elif time[u] + adj[u][v] == time[v]:
ways[v] = (ways[v] + ways[u]) % mod
return ways[n - 1]
N = 7
M = 10
edges = [[0, 6, 7], [0, 1, 2], [1, 2, 3], [1, 3, 3], [6, 3, 3], [3, 5, 1], [6, 5, 1], [2, 5, 1], [0, 4, 5], [4, 6, 2]]
print(countPaths(N, edges))
# This code is contributed by ksam24000
// C# code to implement the approach
using System;
using System.Collections.Generic;
public class GFG {
// Function to get the minimum position
static int getmin(long[] dist, bool[] visited, int n)
{
long x = long.MaxValue;
int pos = 0;
for (int i = 0; i < n; i++) {
if (!visited[i] && dist[i] < x) {
x = dist[i];
pos = i;
}
}
return pos;
}
// Function to count number of paths
static int countPaths(int n, List<List<int> > roads)
{
int mod = (int)1e7;
long MMAX = (long)1e17;
int[, ] adj = new int[n, n];
foreach(List<int> road in roads)
{
int u = road[0];
int v = road[1];
int t = road[2];
adj[u, v] = t;
adj[v, u] = t;
}
bool[] visited = new bool[n];
long[] time = new long[n];
Array.Fill(time, MMAX);
long[] ways = new long[n];
time[0] = 0;
ways[0] = 1;
for (int i = 0; i < n - 1; i++) {
// Find the intersection with minimum
// time to travel
int u = getmin(time, visited, n);
visited[u] = true;
for (int v = 0; v < n; v++) {
if (!visited[v] && adj[u, v] != 0
&& time[u] != MMAX) {
if (time[u] + adj[u, v] < time[v]) {
time[v] = time[u] + adj[u, v];
ways[v] = ways[u];
}
else if (time[u] + adj[u, v]
== time[v]) {
ways[v] = ways[v] + ways[u];
ways[v] %= mod;
}
}
}
}
return (int)ways[n - 1];
}
static public void Main()
{
// Code
int N = 7, M = 10;
List<List<int> > edges = new List<List<int> >();
edges.Add(new List<int>() { 0, 6, 7 });
edges.Add(new List<int>() { 0, 1, 2 });
edges.Add(new List<int>() { 1, 2, 3 });
edges.Add(new List<int>() { 1, 3, 3 });
edges.Add(new List<int>() { 6, 3, 3 });
edges.Add(new List<int>() { 3, 5, 1 });
edges.Add(new List<int>() { 6, 5, 1 });
edges.Add(new List<int>() { 2, 5, 1 });
edges.Add(new List<int>() { 0, 4, 5 });
edges.Add(new List<int>() { 4, 6, 2 });
// Function Call
Console.WriteLine(countPaths(N, edges));
}
}
// This code is contributed by lokeshmvs21.
// JavaScript implementation of the approach
// Function to get the minimum position
function getmin(dist, visited) {
let x = Number.MAX_SAFE_INTEGER, pos;
for (let i = 0; i < dist.length; i++) {
if (!visited[i] && dist[i] < x) {
x = dist[i];
pos = i;
}
}
return pos;
}
// Function to count number of paths
function countPaths(n, roads) {
const mod = 1e9 + 7;
const MMAX = 1e17;
let adj = new Array(n);
for (let i = 0; i < n; i++) {
adj[i] = new Array(n).fill(0);
}
for (let i = 0; i < roads.length; i++) {
let u = roads[i][0];
let v = roads[i][1];
let t = roads[i][2];
adj[u][v] = t;
adj[v][u] = t;
}
let visited = new Array(n).fill(false);
let time = new Array(n).fill(MMAX);
let ways = new Array(n).fill(0);
time[0] = 0;
ways[0] = 1;
for (let i = 0; i < n - 1; i++) {
// Find the intersection with minimum
// time to travel
let u = getmin(time, visited);
visited[u] = true;
for (let v = 0; v < n; v++) {
if (!visited[v] && adj[u][v] && time[u] !== MMAX) {
if (time[u] + adj[u][v] < time[v]) {
time[v] = time[u] + adj[u][v];
ways[v] = ways[u];
}
else if (time[u] + adj[u][v] === time[v]) {
ways[v] = (ways[v] + ways[u]) % mod;
}
}
}
}
return ways[n - 1];
}
// Example usage
let N = 7, M = 10;
let edges = [ [0, 6, 7], [0, 1, 2], [1, 2, 3], [1, 3, 3],
[6, 3, 3], [3, 5, 1], [6, 5, 1], [2, 5, 1], [0, 4, 5], [4, 6, 2] ];
console.log(countPaths(N, edges));
Output
4
Time complexity: As we check the node with minimum time to travel each time it takes O(n) time and we have to run this algorithm (v-1) times to find the minimum time of every nodes. So the total time complexity will be O(n*(n - 1)) ? O(n2).
Auxiliary Space: As we keep track of three extra arrays(time[], ways[], visited[]) and an adjacency matrix the space complexity is O(v2+3*v).
Efficient approach: To solve the problem follow the below idea:
As discussed in previous approach to get the intersection with smallest travel time we can now get that efficiently by using a min heap . As we start minimizing the travel time we add those intersections in a priority queue and take the intersection with minimum time to travel.
Follow the below steps to solve the problem:
- First, we make an adjacency list from the edges array
- Now we create a min heap which stores the {minimum_time_to_travel_intersection, intersection_number}
- Now every time we takeout the intersection with minimum_time_to_travel and minimize its adjacent intersections time
- If (time[u]+time_taken(u, v) < time[v]) , then ways[v] = ways[u]
- If (time[u] + time_taken(u, v) == time[v]), then ways[v] = ways[v] + ways[u]
Below is the implementation of the above approach:
// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
// Function to count number of paths
int countPaths(int n, vector<vector<int> >& roads)
{
int mod = 1e9 + 7;
vector<vector<pair<int, int> > > graph(n);
for (auto& road : roads) {
graph[road[0]].push_back({ road[1], road[2] });
graph[road[1]].push_back({ road[0], road[2] });
}
vector<long long> distance(n, LONG_MAX);
vector<int> path(n, 0);
priority_queue<pair<long long, int>,
vector<pair<long long, int> >,
greater<pair<long long, int> > >
pq;
pq.push({ 0, 0 });
distance[0] = 0;
path[0] = 1;
while (!pq.empty()) {
pair<long long, int> t = pq.top();
pq.pop();
for (auto& nbr : graph[t.second]) {
long long vert = nbr.first;
long long edge = nbr.second;
if (distance[vert]
> distance[t.second] + edge) {
distance[vert] = distance[t.second] + edge;
pq.push({ distance[vert], vert });
path[vert] = path[t.second] % mod;
}
else if (distance[vert] == t.first + edge) {
path[vert] += path[t.second];
path[vert] %= mod;
}
}
}
return path[n - 1];
}
// Driver Code
int main()
{
int n = 7, m = 10;
vector<vector<int> > roads
= { { 0, 6, 7 }, { 0, 1, 2 }, { 1, 2, 3 }, { 1, 3, 3 }, { 6, 3, 3 }, { 3, 5, 1 }, { 6, 5, 1 }, { 2, 5, 1 }, { 0, 4, 5 }, { 4, 6, 2 } };
// Function call
cout << countPaths(n, roads) << endl;
return 0;
}
// Java code to implement the approach
import java.io.*;
import java.util.*;
class GFG {
static final int mod = (int)(1e9 + 7);
// Function to count number of paths
static int countPaths(int n, int[][] roads)
{
List<List<int[]> > graph = new ArrayList<>();
for (int i = 0; i < n; i++)
graph.add(new ArrayList<>());
for (int[] road : roads) {
graph.get(road[0]).add(
new int[] { road[1], road[2] });
graph.get(road[1]).add(
new int[] { road[0], road[2] });
}
long[] distance = new long[n];
Arrays.fill(distance, Long.MAX_VALUE);
int[] path = new int[n];
PriorityQueue<long[]> pq = new PriorityQueue<>(
(a, b) -> (int)(a[0] - b[0]));
pq.offer(new long[] { 0, 0 });
distance[0] = 0;
path[0] = 1;
while (!pq.isEmpty()) {
long[] t = pq.poll();
for (int[] nbr : graph.get((int)t[1])) {
int vert = nbr[0];
int edge = nbr[1];
if (distance[vert]
> distance[(int)t[1]] + edge) {
distance[vert]
= distance[(int)t[1]] + edge;
pq.offer(new long[] { distance[vert],
vert });
path[vert] = path[(int)t[1]] % mod;
}
else if (distance[vert] == t[0] + edge) {
path[vert]
= (path[vert] + path[(int)t[1]])
% mod;
}
}
}
return path[n - 1];
}
public static void main(String[] args)
{
int n = 7, m = 10;
int[][] roads
= { { 0, 6, 7 }, { 0, 1, 2 }, { 1, 2, 3 },
{ 1, 3, 3 }, { 6, 3, 3 }, { 3, 5, 1 },
{ 6, 5, 1 }, { 2, 5, 1 }, { 0, 4, 5 },
{ 4, 6, 2 } };
// Function call
System.out.println(countPaths(n, roads));
}
}
// This code is contributed by karthik.
import heapq
# Function to count number of paths
def countPaths(n, roads):
mod = int(1e9 + 7)
graph = [[] for i in range(n)]
for road in roads:
graph[road[0]].append((road[1], road[2]))
graph[road[1]].append((road[0], road[2]))
distance = [float('inf') for i in range(n)]
path = [0 for i in range(n)]
heap = [(0, 0)]
heapq.heapify(heap)
distance[0] = 0
path[0] = 1
while heap:
t = heapq.heappop(heap)
for nbr in graph[t[1]]:
vert = nbr[0]
edge = nbr[1]
if distance[vert] > distance[t[1]] + edge:
distance[vert] = distance[t[1]] + edge
heapq.heappush(heap, (distance[vert], vert))
path[vert] = path[t[1]] % mod
elif distance[vert] == t[0] + edge:
path[vert] += path[t[1]]
path[vert] %= mod
return path[n - 1]
# Driver Code
if __name__ == "__main__":
n = 7
m = 10
roads = [[0, 6, 7], [0, 1, 2], [1, 2, 3], [1, 3, 3], [6, 3, 3], [3, 5, 1], [6, 5, 1], [2, 5, 1], [0, 4, 5], [4, 6, 2]]
# Function call
print(countPaths(n, roads))
# This code is contributed by Vikram_Shirsat
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
// C# code to implement the approach
class HelloWorld {
// custom sort function.
class GFG : IComparer<KeyValuePair<int,int>>
{
public int Compare(KeyValuePair<int,int> x, KeyValuePair<int,int> y)
{
if (x.Key == y.Key)
{
return x.Value.CompareTo(y.Value);
}
// CompareTo() method
return x.Key.CompareTo(y.Key);
}
}
// Function to count number of paths
static int countPaths(int n, int m, int[][] road)
{
int mod = 1000000007;
List<KeyValuePair<int,int>>[] graph = new List<KeyValuePair<int,int>>[n];
for(int i = 0; i < n; i++){
graph[i] = new List<KeyValuePair<int, int>>();
}
for(int i = 0; i < m; i++){
graph[road[i][0]].Add(new KeyValuePair<int,int> (road[i][1], road[i][2]));
graph[road[i][1]].Add(new KeyValuePair<int,int> (road[i][0], road[i][2]));
}
int[] distance = new int[n];
for(int i = 0; i < n; i++){
distance[i] = 500000;
}
int[] path = new int[n];
for(int i = 0; i < n; i++){
path[i] = 0;
}
List<KeyValuePair<int,int>> pq = new List<KeyValuePair<int,int>>();
pq.Add(new KeyValuePair<int, int>(0, 0));
distance[0] = 0;
path[0] = 1;
GFG gg = new GFG();
while (pq.Count > 0) {
KeyValuePair<int, int> t = pq[0];
pq.RemoveAt(0);
for(int i = 0; i < graph[t.Value].Count; i++){
KeyValuePair<int,int> nbr = graph[t.Value][i];
int vert = nbr.Key;
int edge = nbr.Value;
if (distance[vert] > distance[t.Value] + edge) {
distance[vert] = distance[t.Value] + edge;
pq.Add(new KeyValuePair<int, int> (distance[vert], vert ));
pq.Sort(gg);
path[vert] = path[t.Value] % mod;
}
else if (distance[vert] == t.Key + edge) {
path[vert] += path[t.Value];
path[vert] %= mod;
}
}
}
return path[n - 1];
}
static void Main() {
int n = 7;
int m = 10;
int[][] roads = new int[][] {
new int[] { 0, 6, 7 },
new int[] { 0, 1, 2 },
new int[] { 1, 2, 3 },
new int[] { 1, 3, 3 },
new int[] { 6, 3, 3 },
new int[] { 3, 5, 1 },
new int[] { 6, 5, 1 },
new int[] {2, 5, 1 },
new int[] {0, 4, 5},
new int[] {4, 6, 2}
};
// Function call
Console.WriteLine(countPaths(n, m, roads));
}
}
// The code is contributed by Nidhi goel.
// javascript code to implement the approach
// Function to count number of paths
function countPaths(n, roads)
{
let mod = 1e9 + 7;
let graph = new Array(n);
for(let i = 0; i < n; i++){
graph[i] = new Array();
}
for (let i = 0; i < roads.length; i++) {
let road = roads[i];
graph[road[0]].push([road[1], road[2]]);
graph[road[1]].push([road[0], road[2]]);
}
let distance = new Array(n).fill(2000);
let path = new Array(n).fill(0);
let pq = [];
pq.push([0,0]);
distance[0] = 0;
path[0] = 1;
while (pq.length > 0) {
let t = pq[0];
pq.shift();
for(let i = 0; i < graph[t[1]].length; i++){
let nbr = graph[t[1]][i];
let vert = nbr[0];
let edge = nbr[1];
if (distance[vert] > distance[t[1]] + edge) {
distance[vert] = distance[t[1]] + edge;
pq.push([distance[vert], vert]);
pq.sort(function(x, y){
if(x[0] == y[0]){
return x[1] - y[1];
}
return x[0] - y[0];
}
)
path[vert] = path[t[1]] % mod;
}
else if (distance[vert] == t[0] + edge) {
path[vert] += path[t[1]];
path[vert] %= mod;
}
}
}
return path[n - 1];
}
// Driver Code
let n = 7, m = 10;
let roads = [ [ 0, 6, 7 ], [ 0, 1, 2 ], [ 1, 2, 3 ], [ 1, 3, 3 ], [ 6, 3, 3 ], [ 3, 5, 1 ], [ 6, 5, 1 ], [ 2, 5, 1 ], [ 0, 4, 5 ], [ 4, 6, 2 ] ];
// Function call
console.log(countPaths(n, roads));
// The code is contributed by Nidhi goel.
Output
4
Time complexity: As we will traverse every edge and use min heap to store intersections, the Time complexity is O(M+NlogN) where M is the number of edges and N is the number of intersections.
Auxiliary Space: We will need an adjacency list that takes O(M+N) space and three arrays with length N. So we can tell that the space complexity will be O(M+N).
Related articles: