Given three arrays A[], B[] and C[] of same size N. The task is to minimize the sum after choosing N elements from these array such that at every index i an element from any one of the array A[i], B[i] or C[i] can be chosen and no two consecutive elements can be chosen from the same array.
Examples:
Input: A[] = {1, 100, 1}, B[] = {100, 100, 100}, C[] = {100, 100, 100}
Output: 102
A[0] + B[1] + A[2] = 1 + 100 + 100 = 201
A[0] + B[1] + C[2] = 1 + 100 + 100 = 201
A[0] + C[1] + B[2] = 1 + 100 + 100 = 201
A[0] + C[1] + A[2] = 1 + 100 + 1 = 102
B[0] + A[1] + B[2] = 100 + 100 + 100 = 300
B[0] + A[1] + C[2] = 100 + 100 + 100 = 300
B[0] + C[1] + A[2] = 100 + 100 + 1 = 201
B[0] + C[1] + B[2] = 100 + 100 + 100 = 300
C[0] + A[1] + B[2] = 100 + 100 + 100 = 300
C[0] + A[1] + C[2] = 100 + 100 + 100 = 300
C[0] + B[1] + A[2] = 100 + 100 + 1 = 201
C[0] + B[1] + C[2] = 100 + 100 + 100 = 300
Input: A[] = {1, 1, 1}, B[] = {1, 1, 1}, C[] = {1, 1, 1}
Output: 3
Approach: The problem is a simple variation of finding minimum cost. The extra constraint are that if we take an element from a particular array then we cannot take the next element from the same array. This could easily be solved using recursion but it would give time complexity as O(3^n) because for every element we have three arrays as choices.
To improve the time complexity we can easily store the pre-calculated values in a dp array.
Since there are three arrays to choose from at every index, three cases arise in this scenario:
- Case 1: If array A[] is selected from the ith element then we either choose the array B[] or the array C[] for the (i + 1)th element.
- Case 2: If array B[] is selected from the ith element then we either choose the array A[] or the array C[] for the (i + 1)th element.
- Case 3: If array C[] is selected from the ith element then we either choose the array A[] or the array B[] for the (i + 1)th element.
The above states can be solved using recursion and intermediate results can be stored in the dp array.
Below is the implementation of the above approach:
C++
// C++ implementation of the above approach #include <bits/stdc++.h> using namespace std; #define SIZE 3 const int N = 3; // Function to return the minimized sum int minSum( int A[], int B[], int C[], int i, int n, int curr, int dp[SIZE][N]) { // If all the indices have been used if (n <= 0) return 0; // If this value is pre-calculated // then return its value from dp array // instead of re-computing it if (dp[n][curr] != -1) return dp[n][curr]; // Here curr is the array chosen // for the (i - 1)th element // 0 for A[], 1 for B[] and 2 for C[] // If A[i - 1] was chosen previously then // only B[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 0) { return dp[n][curr] = min(B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); } // If B[i - 1] was chosen previously then // only A[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 1) return dp[n][curr] = min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); // If C[i - 1] was chosen previously then // only A[i] or B[i] can chosen now // choose the one which leads // to the minimum sum return dp[n][curr] = min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp)); } // Driver code int main() { int A[] = { 1, 50, 1 }; int B[] = { 50, 50, 50 }; int C[] = { 50, 50, 50 }; // Initialize the dp[][] array int dp[SIZE][N]; for ( int i = 0; i < SIZE; i++) for ( int j = 0; j < N; j++) dp[i][j] = -1; // min(start with A[0], start with B[0], start with C[0]) cout << min(A[0] + minSum(A, B, C, 1, SIZE - 1, 0, dp), min(B[0] + minSum(A, B, C, 1, SIZE - 1, 1, dp), C[0] + minSum(A, B, C, 1, SIZE - 1, 2, dp))); return 0; } |
Java
// Java implementation of the above approach import java.io.*; class GFG { static int SIZE = 3 ; static int N = 3 ; // Function to return the minimized sum static int minSum( int A[], int B[], int C[], int i, int n, int curr, int [][]dp) { // If all the indices have been used if (n <= 0 ) return 0 ; // If this value is pre-calculated // then return its value from dp array // instead of re-computing it if (dp[n][curr] != - 1 ) return dp[n][curr]; // Here curr is the array chosen // for the (i - 1)th element // 0 for A[], 1 for B[] and 2 for C[] // If A[i - 1] was chosen previously then // only B[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 0 ) { return dp[n][curr] = Math.min(B[i] + minSum(A, B, C, i + 1 , n - 1 , 1 , dp), C[i] + minSum(A, B, C, i + 1 , n - 1 , 2 , dp)); } // If B[i - 1] was chosen previously then // only A[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 1 ) return dp[n][curr] = Math.min(A[i] + minSum(A, B, C, i + 1 , n - 1 , 0 , dp), C[i] + minSum(A, B, C, i + 1 , n - 1 , 2 , dp)); // If C[i - 1] was chosen previously then // only A[i] or B[i] can chosen now // choose the one which leads // to the minimum sum return dp[n][curr] = Math.min(A[i] + minSum(A, B, C, i + 1 , n - 1 , 0 , dp), B[i] + minSum(A, B, C, i + 1 , n - 1 , 1 , dp)); } // Driver code public static void main (String[] args) { int A[] = { 1 , 50 , 1 }; int B[] = { 50 , 50 , 50 }; int C[] = { 50 , 50 , 50 }; // Initialize the dp[][] array int dp[][] = new int [SIZE][N]; for ( int i = 0 ; i < SIZE; i++) for ( int j = 0 ; j < N; j++) dp[i][j] = - 1 ; // min(start with A[0], start with B[0], start with C[0]) System.out.println(Math.min(A[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 0 , dp), Math.min(B[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 1 , dp), C[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 2 , dp)))); } } // This code is contributed by anuj_67.. |
Python3
# Python3 implementation of the above approach import numpy as np SIZE = 3 ; N = 3 ; # Function to return the minimized sum def minSum(A, B, C, i, n, curr, dp) : # If all the indices have been used if (n < = 0 ) : return 0 ; # If this value is pre-calculated # then return its value from dp array # instead of re-computing it if (dp[n][curr] ! = - 1 ) : return dp[n][curr]; # Here curr is the array chosen # for the (i - 1)th element # 0 for A[], 1 for B[] and 2 for C[] # If A[i - 1] was chosen previously then # only B[i] or C[i] can chosen now # choose the one which leads # to the minimum sum if (curr = = 0 ) : dp[n][curr] = min ( B[i] + minSum(A, B, C, i + 1 , n - 1 , 1 , dp), C[i] + minSum(A, B, C, i + 1 , n - 1 , 2 , dp)); return dp[n][curr] # If B[i - 1] was chosen previously then # only A[i] or C[i] can chosen now # choose the one which leads # to the minimum sum if (curr = = 1 ) : dp[n][curr] = min (A[i] + minSum(A, B, C, i + 1 , n - 1 , 0 , dp), C[i] + minSum(A, B, C, i + 1 , n - 1 , 2 , dp)); return dp[n][curr] # If C[i - 1] was chosen previously then # only A[i] or B[i] can chosen now # choose the one which leads # to the minimum sum dp[n][curr] = min (A[i] + minSum(A, B, C, i + 1 , n - 1 , 0 , dp), B[i] + minSum(A, B, C, i + 1 , n - 1 , 1 , dp)); return dp[n][curr] # Driver code if __name__ = = "__main__" : A = [ 1 , 50 , 1 ]; B = [ 50 , 50 , 50 ]; C = [ 50 , 50 , 50 ]; # Initialize the dp[][] array dp = np.zeros((SIZE,N)); for i in range (SIZE) : for j in range (N) : dp[i][j] = - 1 ; # min(start with A[0], start with B[0], start with C[0]) print ( min (A[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 0 , dp), min (B[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 1 , dp), C[ 0 ] + minSum(A, B, C, 1 , SIZE - 1 , 2 , dp)))); # This code is contributed by AnkitRai01 |
C#
// C# implementation of the above approach using System; class GFG { static int SIZE = 3; static int N = 3; // Function to return the minimized sum static int minSum( int []A, int []B, int []C, int i, int n, int curr, int [,]dp) { // If all the indices have been used if (n <= 0) return 0; // If this value is pre-calculated // then return its value from dp array // instead of re-computing it if (dp[n,curr] != -1) return dp[n,curr]; // Here curr is the array chosen // for the (i - 1)th element // 0 for A[], 1 for B[] and 2 for C[] // If A[i - 1] was chosen previously then // only B[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 0) { return dp[n,curr] = Math.Min(B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); } // If B[i - 1] was chosen previously then // only A[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 1) return dp[n,curr] = Math.Min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); // If C[i - 1] was chosen previously then // only A[i] or B[i] can chosen now // choose the one which leads // to the minimum sum return dp[n,curr] = Math.Min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp)); } // Driver code public static void Main () { int []A = { 1, 50, 1 }; int []B = { 50, 50, 50 }; int []C = { 50, 50, 50 }; // Initialize the dp[][] array int [,]dp = new int [SIZE,N]; for ( int i = 0; i < SIZE; i++) for ( int j = 0; j < N; j++) dp[i,j] = -1; // min(start with A[0], start with B[0], start with C[0]) Console.WriteLine(Math.Min(A[0] + minSum(A, B, C, 1, SIZE - 1, 0, dp), Math.Min(B[0] + minSum(A, B, C, 1, SIZE - 1, 1, dp), C[0] + minSum(A, B, C, 1, SIZE - 1, 2, dp)))); } } // This code is contributed by anuj_67.. |
Javascript
<script> // Javascript implementation of the above approach let SIZE = 3; let N = 3; // Function to return the minimized sum function minSum(A, B, C, i, n, curr, dp) { // If all the indices have been used if (n <= 0) return 0; // If this value is pre-calculated // then return its value from dp array // instead of re-computing it if (dp[n][curr] != -1) return dp[n][curr]; // Here curr is the array chosen // for the (i - 1)th element // 0 for A[], 1 for B[] and 2 for C[] // If A[i - 1] was chosen previously then // only B[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 0) { return dp[n][curr] = Math.min(B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); } // If B[i - 1] was chosen previously then // only A[i] or C[i] can chosen now // choose the one which leads // to the minimum sum if (curr == 1) return dp[n][curr] = Math.min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), C[i] + minSum(A, B, C, i + 1, n - 1, 2, dp)); // If C[i - 1] was chosen previously then // only A[i] or B[i] can chosen now // choose the one which leads // to the minimum sum return dp[n][curr] = Math.min(A[i] + minSum(A, B, C, i + 1, n - 1, 0, dp), B[i] + minSum(A, B, C, i + 1, n - 1, 1, dp)); } let A = [ 1, 50, 1 ]; let B = [ 50, 50, 50 ]; let C = [ 50, 50, 50 ]; // Initialize the dp[][] array let dp = new Array(SIZE); for (let i = 0; i < SIZE; i++) { dp[i] = new Array(N); for (let j = 0; j < N; j++) { dp[i][j] = -1; } } // min(start with A[0], start with B[0], start with C[0]) document.write(Math.min(A[0] + minSum(A, B, C, 1, SIZE - 1, 0, dp), Math.min(B[0] + minSum(A, B, C, 1, SIZE - 1, 1, dp), C[0] + minSum(A, B, C, 1, SIZE - 1, 2, dp)))); </script> |
52
Time Complexity: O(SIZE*N), where dp operations taking SIZE*N time
Auxiliary Space: O(SIZE*N), where dp array is made of two states SIZE*N
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a DP to store the solution of the subproblems.
- Initialize the DP with base cases
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP.
- Return the final solution minimum of min(dp[0][0], min(dp[0][1], dp[0][2])).
Implementation :
C++
#include <iostream> using namespace std; const int SIZE = 3; // Function to return the minimized sum int minSum( int A[], int B[], int C[]) { int dp[SIZE][3]; // Base case dp[SIZE-1][0] = A[SIZE-1]; dp[SIZE-1][1] = B[SIZE-1]; dp[SIZE-1][2] = C[SIZE-1]; // Tabulate the solution from bottom up for ( int i = SIZE-2; i >= 0; i--) { // iterate over subproblems to get the current // value from previous computaions dp[i][0] = A[i] + min(dp[i+1][1], dp[i+1][2]); dp[i][1] = B[i] + min(dp[i+1][0], dp[i+1][2]); dp[i][2] = C[i] + min(dp[i+1][0], dp[i+1][1]); } // Return the minimized sum return min(dp[0][0], min(dp[0][1], dp[0][2])); } // Driver code int main() { int A[] = { 1, 50, 1 }; int B[] = { 50, 50, 50 }; int C[] = { 50, 50, 50 }; // function call cout << minSum(A, B, C) << endl; return 0; } |
Java
// Java program to return the minimized sum public class Main { public static void main(String[] args) { int SIZE = 3 ; int [] A = { 1 , 50 , 1 }; int [] B = { 50 , 50 , 50 }; int [] C = { 50 , 50 , 50 }; int [][] dp = new int [SIZE][ 3 ]; // Base case dp[SIZE - 1 ][ 0 ] = A[SIZE - 1 ]; dp[SIZE - 1 ][ 1 ] = B[SIZE - 1 ]; dp[SIZE - 1 ][ 2 ] = C[SIZE - 1 ]; // Tabulate the solution from bottom up for ( int i = SIZE - 2 ; i >= 0 ; i--) { // Iterate over subproblems to get the current // value from previous computations dp[i][ 0 ] = A[i] + Math.min(dp[i + 1 ][ 1 ], dp[i + 1 ][ 2 ]); dp[i][ 1 ] = B[i] + Math.min(dp[i + 1 ][ 0 ], dp[i + 1 ][ 2 ]); dp[i][ 2 ] = C[i] + Math.min(dp[i + 1 ][ 0 ], dp[i + 1 ][ 1 ]); } // Return the minimized sum int result = Math.min(dp[ 0 ][ 0 ], Math.min(dp[ 0 ][ 1 ], dp[ 0 ][ 2 ])); System.out.println(result); } } |
Python3
import sys SIZE = 3 # Function to return the minimized sum def minSum(A, B, C): dp = [[ 0 for j in range ( 3 )] for i in range (SIZE)] # Base case dp[SIZE - 1 ][ 0 ] = A[SIZE - 1 ] dp[SIZE - 1 ][ 1 ] = B[SIZE - 1 ] dp[SIZE - 1 ][ 2 ] = C[SIZE - 1 ] # Tabulate the solution from bottom up for i in range (SIZE - 2 , - 1 , - 1 ): # iterate over subproblems to get the current # value from previous computaions dp[i][ 0 ] = A[i] + min (dp[i + 1 ][ 1 ], dp[i + 1 ][ 2 ]) dp[i][ 1 ] = B[i] + min (dp[i + 1 ][ 0 ], dp[i + 1 ][ 2 ]) dp[i][ 2 ] = C[i] + min (dp[i + 1 ][ 0 ], dp[i + 1 ][ 1 ]) # Return the minimized sum return min (dp[ 0 ][ 0 ], min (dp[ 0 ][ 1 ], dp[ 0 ][ 2 ])) # Driver code if __name__ = = '__main__' : A = [ 1 , 50 , 1 ] B = [ 50 , 50 , 50 ] C = [ 50 , 50 , 50 ] # function call print (minSum(A, B, C)) |
C#
using System; class Program { const int SIZE = 3; // Function to return the minimized sum static int MinSum( int [] A, int [] B, int [] C) { int [,] dp = new int [SIZE, 3]; // Base case dp[SIZE - 1, 0] = A[SIZE - 1]; dp[SIZE - 1, 1] = B[SIZE - 1]; dp[SIZE - 1, 2] = C[SIZE - 1]; // Tabulate the solution from bottom up for ( int i = SIZE - 2; i >= 0; i--) { // Iterate over subproblems to get the current // value from previous computations dp[i, 0] = A[i] + Math.Min(dp[i + 1, 1], dp[i + 1, 2]); dp[i, 1] = B[i] + Math.Min(dp[i + 1, 0], dp[i + 1, 2]); dp[i, 2] = C[i] + Math.Min(dp[i + 1, 0], dp[i + 1, 1]); } // Return the minimized sum return Math.Min(dp[0, 0], Math.Min(dp[0, 1], dp[0, 2])); } // Driver Code static void Main() { int [] A = { 1, 50, 1 }; int [] B = { 50, 50, 50 }; int [] C = { 50, 50, 50 }; // Function call Console.WriteLine(MinSum(A, B, C)); } } |
Javascript
const SIZE = 3; // Function to return the minimized sum function minSum(A, B, C) { const dp = new Array(SIZE).fill().map(() => new Array(3)); // Base case dp[SIZE - 1][0] = A[SIZE - 1]; dp[SIZE - 1][1] = B[SIZE - 1]; dp[SIZE - 1][2] = C[SIZE - 1]; // Tabulate the solution from bottom up for (let i = SIZE - 2; i >= 0; i--) { // Iterate over subproblems to get the current // value from previous computations dp[i][0] = A[i] + Math.min(dp[i + 1][1], dp[i + 1][2]); dp[i][1] = B[i] + Math.min(dp[i + 1][0], dp[i + 1][2]); dp[i][2] = C[i] + Math.min(dp[i + 1][0], dp[i + 1][1]); } // Return the minimized sum return Math.min(dp[0][0], Math.min(dp[0][1], dp[0][2])); } // Driver code const A = [1, 50, 1]; const B = [50, 50, 50]; const C = [50, 50, 50]; // Function call console.log(minSum(A, B, C)); |
52
Time Complexity: O(n), where n is the size of the arrays A, B, and C.
Auxiliary Space: O(n), as the dp array has n rows and 3 columns
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!