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++ 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 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 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# 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.. |
<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 :
#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 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);
}
} |
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))
|
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));
}
} |
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