Count ways to reach destination of given Graph in minimum time
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++
// 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
// 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 |
Python3
# 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#
// 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
// 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)); |
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++
// 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
// 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. |
Python3
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 |
C#
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
// 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. |
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:
Please Login to comment...