Given an unweighted directed graph with N vertices and M edges and array A[] of size N. Given Q queries of the form (U, V), the task for this problem is for every query to print the shortest path from U to V and print the maximum coins collected for that shortest path. For visiting, Node ‘i’ collects A[i] coins. If traveling from U to V is not possible print -1.
Examples:
Input: N = 5, Edg[] = {{1, 2}, {1, 3}, {2, 3}, {3, 4}, {3, 5}, {4, 1}, {5, 1}}, A[] = {30, 50, 70, 20, 60}, Q[] = {{1, 3}, {3, 1}, {4, 5}};
Output: 1 100
2 160
3 180
Explanation:
- Length of Shortest path from 1 to 3 is 1 (1 -> 3) and coins collected = coins at node1 + coins at node3 = 30 + 70 = 100
- Length of Shortest path from 3 to 1 is 2 (3 -> 5 -> 1) and coins collected = coins at node3 + coins at node5 + coins at node1 = 70 + 60 + 30 = 160
- Length of Shortest path from 4 to 5 is 3 (4 -> 1 -> 3 -> 5) and coins collected = coins at node4 + coins at node1 + coins at node3 + coins at node5 = 20 + 30 + 70 + 60 = 180
Input: N2 = 2, Edg[] = {}, A[] = {100, 100}, Q[] = {{1, 2}}
Output: -1
Naive approach: The basic way to solve the problem is as follows:
The basic way to solve this problem is to generate all possible combinations by using a recursive approach.
Time Complexity: O(N!)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized based on the following idea:
Dynamic programming can be used to solve this problem
dp[i][j] represents shortest path from i to j.
Follow the steps below to solve the problem:
- Create dp[N][N] and ANS[N][N] tables with all values set to INT_MAX and INT_MIN.
- Iterate over all M edges and for each edge U and V set dp[U][V] to 1 and ANS[U][V] to A[U] + A[V].
- Fill the dp[N][N] table by iterating on all states.
- Iterate each query and print the answer
Below is the implementation of the above approach:
C++
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std; // To avoid overflow #define int long long // Function for finding shortest paths // with maximized coins void shortPath( int N, vector<vector< int > >& edg, vector< int >& A, vector<vector< int > >& Q) { // Initializing dp table for // finding shortest path vector<vector< int > > dp(N + 1, vector< int >(N + 1, INT_MAX)); // Initializing another table // to store max coins vector<vector< int > > ans(N + 1, vector< int >(N + 1, INT_MIN)); // Iterating over all M edges for ( int i = 0; i < edg.size(); i++) { // There is edge exists from // edg[i][0] to edg[i][1] dp[edg[i][0]][edg[i][1]] = 1; // Answer variable stores ans[edg[i][0]][edg[i][1]] = A[edg[i][0] - 1] + A[edg[i][1] - 1]; } // Inserting from 1 to N for ( int k = 1; k <= N; k++) { // Iterating on all 1 to N for ( int i = 1; i <= N; i++) { // Iterating on all 1 to N for ( int j = 1; j <= N; j++) { // If path through k is // shortest then relax // the weight if (dp[i][j] > dp[i][k] + dp[k][j]) { dp[i][j] = dp[i][k] + dp[k][j]; ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1]; } // Maximise coins else if (dp[i][j] == dp[i][k] + dp[k][j] and ans[i][j] < ans[i][k] + ans[k][j] - A[k - 1]) { ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1]; } } } } // Iterating for all queries for ( int i = 0; i < Q.size(); i++) { // Query int U = Q[i][0], V = Q[i][1]; // Printing answer for query // if it exists if (dp[U][V] <= N * N) cout << dp[U][V] << " " << ans[U][V] << endl; // If no path exists else cout << "-1" << endl; } } // Driver program int32_t main() { // Test case 1 int N1 = 5; vector<vector< int > > edg1 = { { 1, 2 }, { 1, 3 }, { 2, 3 }, { 3, 4 }, { 3, 5 }, { 4, 1 }, { 5, 1 } }; vector< int > A1 = { 30, 50, 70, 20, 60 }; vector<vector< int > > Q1 = { { 1, 3 }, { 3, 1 }, { 4, 5 } }; // Call for test case 1 shortPath(N1, edg1, A1, Q1); cout << endl; // Test case 2 int N2 = 2; vector<vector< int > > edg2 = {}; vector< int > A2 = { 100, 100 }; vector<vector< int > > Q2 = { { 1, 2 } }; // Call for test case 2 shortPath(N2, edg2, A2, Q2); return 0; } |
Java
//Java code for the above approach import java.util.Arrays; class GFG { static void shortPath( int N, int [][] edg, int [] A, int [][] Q) { // Initializing dp table for finding shortest path int [][] dp = new int [N + 1 ][N + 1 ]; int [][] ans = new int [N + 1 ][N + 1 ]; for ( int i = 0 ; i < edg.length; i++) { dp[edg[i][ 0 ]][edg[i][ 1 ]] = 1 ; ans[edg[i][ 0 ]][edg[i][ 1 ]] = A[edg[i][ 0 ] - 1 ] + A[edg[i][ 1 ] - 1 ]; } // Initializing another table to store max coins for ( int k = 1 ; k <= N; k++) { for ( int i = 1 ; i <= N; i++) { for ( int j = 1 ; j <= N; j++) { if (dp[i][k] > 0 && dp[k][j] > 0 ) { // check if i and k, and k and j are // connected if (dp[i][j] == 0 || dp[i][j] > dp[i][k] + dp[k][j]) { dp[i][j] = dp[i][k] + dp[k][j]; ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1 ]; } else if (dp[i][j] == dp[i][k] + dp[k][j] && ans[i][j] < ans[i][k] + ans[k][j] - A[k - 1 ]) { ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1 ]; } } } } } for ( int i = 0 ; i < Q.length; i++) { // Printing answer for query // if it exists int U = Q[i][ 0 ]; int V = Q[i][ 1 ]; if (dp[U][V] > 0 && dp[U][V] <= N * N) { System.out.println(dp[U][V] + " " + ans[U][V]); } else { // If no path exists System.out.println( "-1" ); } } } // Driver program public static void main(String[] args) { // Test case 1 int N1 = 5 ; int [][] edg1 = { { 1 , 2 }, { 1 , 3 }, { 2 , 3 }, { 3 , 4 }, { 3 , 5 }, { 4 , 1 }, { 5 , 1 } }; int [] A1 = { 30 , 50 , 70 , 20 , 60 }; int [][] Q1 = { { 1 , 3 }, { 3 , 1 }, { 4 , 5 } }; // Call for test case 1 shortPath(N1, edg1, A1, Q1); System.out.println(); // Test case 2 int N2 = 2 ; int [][] edg2 = {}; int [] A2 = { 100 , 100 }; int [][] Q2 = {{ 1 , 2 }}; // Call for test case 2 shortPath(N2, edg2, A2, Q2); System.out.println(); } } // This code is contributed by Pushpesh Raj. |
Python3
#Python code for the above approach: import sys # To avoid overflow sys.setrecursionlimit( 10 * * 7 ) def shortPath(N, edg, A, Q): # Initializing dp table for # finding shortest path dp = [[ float ( "inf" ) for j in range (N + 1 )] for i in range (N + 1 )] # Initializing another table # to store max coins ans = [[ - sys.maxsize for j in range (N + 1 )] for i in range (N + 1 )] # Iterating over all M edges for i in range ( len (edg)): # There is edge exists from # edg[i][0] to edg[i][1] dp[edg[i][ 0 ]][edg[i][ 1 ]] = 1 # Answer variable stores ans[edg[i][ 0 ]][edg[i][ 1 ]] = A[edg[i][ 0 ] - 1 ] + A[edg[i][ 1 ] - 1 ] # Inserting from 1 to N for k in range ( 1 , N + 1 ): # Iterating on all 1 to N for i in range ( 1 , N + 1 ): # Iterating on all 1 to N for j in range ( 1 , N + 1 ): # If path through k is # shortest then relax # the weight if dp[i][j] > dp[i][k] + dp[k][j]: dp[i][j] = dp[i][k] + dp[k][j] ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1 ] # Maximise coins elif (dp[i][j] = = dp[i][k] + dp[k][j] and ans[i][j] < ans[i][k] + ans[k][j] - A[k - 1 ]): ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1 ] # Iterating for all queries for i in range ( len (Q)): # Query U = Q[i][ 0 ] V = Q[i][ 1 ] # Printing answer for query # if it exists if dp[U][V] < = N * N: print (dp[U][V], ans[U][V]) # If no path exists else : print ( "-1" ) # Test case 1 N1 = 5 edg1 = [[ 1 , 2 ], [ 1 , 3 ], [ 2 , 3 ], [ 3 , 4 ], [ 3 , 5 ], [ 4 , 1 ], [ 5 , 1 ]] A1 = [ 30 , 50 , 70 , 20 , 60 ] Q1 = [[ 1 , 3 ], [ 3 , 1 ], [ 4 , 5 ]] # Call for test case 1 shortPath(N1, edg1, A1, Q1) print () # Test case 2 N2 = 2 edg2 = [] A2 = [ 100 , 100 ] Q2 = [[ 1 , 2 ]] #Call for test case 2 shortPath(N2, edg2, A2, Q2) print () #This code is contributed by shivamsharma215 |
C#
// C# code for the above approach: using System; class Program { static void shortPath( int N, int [][] edg, int [] A, int [][] Q) { // Initializing dp table for finding shortest path var dp = new int [N + 1, N + 1]; var ans = new int [N + 1, N + 1]; for ( var i = 0; i < edg.Length; i++) { dp[edg[i][0], edg[i][1]] = 1; ans[edg[i][0], edg[i][1]] = A[edg[i][0] - 1] + A[edg[i][1] - 1]; } // Initializing another table to store max coins for ( var k = 1; k <= N; k++) { for ( var i = 1; i <= N; i++) { for ( var j = 1; j <= N; j++) { if (dp[i, k] > 0 && dp[k, j] > 0) { // check if i and k, and k and j are // connected if (dp[i, j] == 0 || dp[i, j] > dp[i, k] + dp[k, j]) { dp[i, j] = dp[i, k] + dp[k, j]; ans[i, j] = ans[i, k] + ans[k, j] - A[k - 1]; } else if (dp[i, j] == dp[i, k] + dp[k, j] && ans[i, j] < ans[i, k] + ans[k, j] - A[k - 1]) { ans[i, j] = ans[i, k] + ans[k, j] - A[k - 1]; } } } } } for ( var i = 0; i < Q.Length; i++) { // Printing answer for query // if it exists var U = Q[i][0]; var V = Q[i][1]; if (dp[U, V] > 0 && dp[U, V] <= N * N) { Console.WriteLine(dp[U, V] + " " + ans[U, V]); } else { // If no path exists Console.WriteLine( "-1" ); } } } // Driver program static void Main() { // Test case 1 var N1 = 5; var edg1 = new int [][] { new int [] { 1, 2 }, new int [] { 1, 3 }, new int [] { 2, 3 }, new int [] { 3, 4 }, new int [] { 3, 5 }, new int [] { 4, 1 }, new int [] { 5, 1 } }; var A1 = new int [] { 30, 50, 70, 20, 60 }; var Q1 = new int [][] { new int [] { 1, 3 }, new int [] { 3, 1 }, new int [] { 4, 5 } }; shortPath(N1, edg1, A1, Q1); // Call for test case 1 Console.WriteLine(); // Test case 2 var N2 = 2; var edg2 = new int [0][]; var A2 = new int [] { 100, 100 }; var Q2 = new int [][] { new int [] { 1, 2 } }; // Call for test case 2 shortPath(N2, edg2, A2, Q2); Console.WriteLine(); } } |
Javascript
// JavaScript code for the above approach: // Function for finding shortest paths // with maximized coins function shortPath(N, edg, A, Q) { // Initializing dp table for // finding shortest path var dp = Array.from({length: N+1}, () => Array(N+1).fill(Number.POSITIVE_INFINITY)); // Initializing another table // to store max coins var ans = Array.from({length: N+1}, () => Array(N+1).fill(-Infinity)); // Iterating over all M edges for ( var i = 0; i < edg.length; i++) { // There is edge exists from // edg[i][0] to edg[i][1] dp[edg[i][0]][edg[i][1]] = 1; // Answer variable stores ans[edg[i][0]][edg[i][1]] = A[edg[i][0] - 1] + A[edg[i][1] - 1]; } // Inserting from 1 to N for ( var k = 1; k <= N; k++) { // Iterating on all 1 to N for ( var i = 1; i <= N; i++) { // Iterating on all 1 to N for ( var j = 1; j <= N; j++) { // If path through k is // shortest then relax // the weight if (dp[i][j] > dp[i][k] + dp[k][j]) { dp[i][j] = dp[i][k] + dp[k][j]; ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1]; } // Maximise coins else if (dp[i][j] == dp[i][k] + dp[k][j] && ans[i][j] < ans[i][k] + ans[k][j] - A[k - 1]) { ans[i][j] = ans[i][k] + ans[k][j] - A[k - 1]; } } } } // Iterating for all queries for ( var i = 0; i < Q.length; i++) { // Query var U = Q[i][0]; var V = Q[i][1]; // Printing answer for query // if it exists if (dp[U][V] <= N * N) { console.log(dp[U][V], ans[U][V]); } // If no path exists else { console.log( "-1" ); } } } // Driver program // Test case 1 var N1 = 5; var edg1 = [[1, 2], [1, 3], [2, 3], [3, 4], [3, 5], [4, 1], [5, 1]]; var A1 = [30, 50, 70, 20, 60]; var Q1 = [[1, 3], [3, 1], [4, 5]]; // Call for test case 1 shortPath(N1, edg1, A1, Q1); console.log(); // Test case 2 var N2 = 2; var edg2 = []; var A2 = [100, 100]; var Q2 = [[1, 2]]; // Call for test case 2 shortPath(N2, edg2, A2, Q2); console.log(); // This code is contributed by Prasad Kandekar(prasad264) |
1 100 2 160 3 180 -1
Time Complexity: O(N3)
Auxiliary Space: O(N2)
Related Articles:
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!