Least cost required to empty an Array by removing elements from front
Given binary array A[] of size N, the task is to find the minimum cost to remove all elements of the array by performing moves (where the cost of the odd move will be the sum of the elements removed and the cost for the even move will be 0). For more clarification:
- First Move: This is an odd move, Remove either 1 or 2 elements from the front of the array and the cost of removing will be equal to the sum of those removed elements.
- Second Move: This is an even move, Remove either 1 or 2 elements from the front of the array and this operation will be performed with cost zero.
- Third Move: This is an odd move, Remove 1 or 2 elements from the front of the array and the cost of removing them will be equal to the sum of those elements.
Examples:
Input: A[] = {1, 0, 1, 1, 0, 1, 1, 1}
Output: 2
Explanation: Following is the optimal way to perform the above operations:
- In first move remove 2 elements that is {1, 0} it will cost 1.
- In the second move remove 2 elements that are {1, 1} it will cost 0.
- In third move remove 2 elements that is {0, 1} it will cost 1.
- In fourth move remove 2 elements that is {1, 1} it will cost 0.
The minimum possible cost to remove all elements is 2.
Input: A[] = {1, 1, 1, 1, 1, 1}
Output: 2
Explanation: Following is the optimal way to perform the above operations:
- In the first move remove 1 element that is {1} it will cost 1.
- In second move remove 2 elements that is {1, 1} it will cost 0.
- In the third move remove 1 element that is {1} it will cost 1.
- In fourth move remove 2 elements that is {1, 1} it will cost 0.
The minimum possible cost to remove all elements is 2.
Naive approach: The basic way to solve the problem is as follows:
The basic way to solve this problem is to explore all possible combinations by using a recursive approach.
Time Complexity: O(2N)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized based on the following idea:
Dynamic programming can be used to solve to this problem.
- dp[i] represents minimum cost till index i
- recurrence relation :
- dp[i] = min(dp[i + 1] + A[i], dp[i + 2] + A[i] + A[i + 1]) when move is odd
- dp[i] = min(dp[i + 1], dp[i + 2]) when move is even
It can be observed that the recursive function is called exponential times. That means that some states are called repeatedly. So the idea is to store the value of each state. This can be done using by store the value of a state and whenever the function is called, return the stored value without computing again.
Follow the steps below to solve the problem:
- Create a recursive function that takes two parameters i representing i’th index of array j representing parity of move either even or odd.
- Call recursive function for both choosing one index and choosing two indexes.
- Check the base case that the array is empty or not and return 0.
- Create a 2d array of dp[N][2] initially filled with -1.
- If the answer for a particular state is computed then save it in dp[i][j].
- If the answer for a particular state is already computed then just return dp[i][j].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int dp[100001][2];
int recur( int i, int j, int A[], int N)
{
if (i == N) {
return 0;
}
if (dp[i][j] != -1)
return dp[i][j];
int ans = INT_MAX;
if (j == 0)
ans = min(ans, recur(i + 1, j ^ 1, A, N) + A[i]);
if (j == 0 and i + 1 < N)
ans = min(ans, recur(i + 2, j ^ 1, A, N) + A[i]
+ A[i + 1]);
if (j == 1)
ans = min(ans, recur(i + 1, j ^ 1, A, N));
if (j == 1 and i + 1 < N)
ans = min(ans, recur(i + 2, j ^ 1, A, N));
return dp[i][j] = ans;
}
void minCost( int A[], int N)
{
memset (dp, -1, sizeof (dp));
cout << recur(0, 0, A, N) << endl;
}
int main()
{
int A[] = { 1, 0, 1, 1, 0, 1, 1, 1 };
int N = sizeof (A) / sizeof (A[0]);
minCost(A, N);
int A1[] = { 1, 1, 1, 1, 1, 1 };
int N1 = sizeof (A1) / sizeof (A1[0]);
minCost(A1, N1);
return 0;
}
|
Java
import java.io.*;
class GFG {
static int dp[][]= new int [ 100001 ][ 2 ];
public static int recur( int i, int j, int A[], int N)
{
if (i == N) {
return 0 ;
}
if (dp[i][j] != - 1 )
return dp[i][j];
int ans = Integer.MAX_VALUE;
if (j == 0 )
ans = Math.min(ans, recur(i + 1 , j ^ 1 , A, N)
+ A[i]);
if (j == 0 && i + 1 < N)
ans = Math.min(ans, recur(i + 2 , j ^ 1 , A, N)
+ A[i] + A[i + 1 ]);
if (j == 1 )
ans = Math.min(ans, recur(i + 1 , j ^ 1 , A, N));
if (j == 1 && i + 1 < N)
ans = Math.min(ans, recur(i + 2 , j ^ 1 , A, N));
return dp[i][j] = ans;
}
public static void minCost( int A[], int N)
{
for ( int i = 0 ; i < 100001 ; i++) {
for ( int j = 0 ; j < 2 ; j++) {
dp[i][j] = - 1 ;
}
}
System.out.println(recur( 0 , 0 , A, N));
}
public static void main(String[] args)
{
int A[] = { 1 , 0 , 1 , 1 , 0 , 1 , 1 , 1 };
int N = A.length;
minCost(A, N);
int A1[] = { 1 , 1 , 1 , 1 , 1 , 1 };
int N1 = A1.length;
minCost(A1, N1);
}
}
|
Python3
dp = [[ - 1 for i in range ( 2 )] for j in range ( 100001 )]
def recur(i: int , j: int , A: list , N: int ) - > int :
if i = = N:
return 0
if dp[i][j] ! = - 1 :
return dp[i][j]
ans = float ( "inf" )
if j = = 0 :
ans = min (ans, recur(i + 1 , j ^ 1 , A, N) + A[i])
if j = = 0 and i + 1 < N:
ans = min (ans, recur(i + 2 , j ^ 1 , A, N) + A[i] + A[i + 1 ])
if j = = 1 :
ans = min (ans, recur(i + 1 , j ^ 1 , A, N))
if j = = 1 and i + 1 < N:
ans = min (ans, recur(i + 2 , j ^ 1 , A, N))
dp[i][j] = ans
return ans
def minCost(A: list , N: int ):
print (recur( 0 , 0 , A, N))
if __name__ = = "__main__" :
A = [ 1 , 0 , 1 , 1 , 0 , 1 , 1 , 1 ]
N = len (A)
minCost(A, N)
A1 = [ 1 , 1 , 1 , 1 , 1 , 1 ]
N1 = len (A1)
minCost(A1, N1)
|
C#
using System;
public class GFG {
static int [, ] dp = new int [100001, 2];
static int recur( int i, int j, int [] A, int N)
{
if (i == N) {
return 0;
}
if (dp[i, j] != -1)
return dp[i, j];
int ans = int .MaxValue;
if (j == 0)
ans = Math.Min(ans, recur(i + 1, j ^ 1, A, N)
+ A[i]);
if (j == 0 && i + 1 < N)
ans = Math.Min(ans, recur(i + 2, j ^ 1, A, N)
+ A[i] + A[i + 1]);
if (j == 1)
ans = Math.Min(ans, recur(i + 1, j ^ 1, A, N));
if (j == 1 && i + 1 < N)
ans = Math.Min(ans, recur(i + 2, j ^ 1, A, N));
return dp[i, j] = ans;
}
static void minCost( int [] A, int N)
{
for ( int i = 0; i < 100001; i++) {
for ( int j = 0; j < 2; j++) {
dp[i, j] = -1;
}
}
Console.WriteLine(recur(0, 0, A, N));
}
static public void Main()
{
int [] A = { 1, 0, 1, 1, 0, 1, 1, 1 };
int N = A.Length;
minCost(A, N);
int [] A1 = { 1, 1, 1, 1, 1, 1 };
int N1 = A1.Length;
minCost(A1, N1);
}
}
|
Javascript
let dp = new Array(100001);
for (let i = 0; i < 100001; i++)
dp[i] = new Array(2);
function recur( i, j, A, N)
{
if (i == N) {
return 0;
}
if (dp[i][j] != -1)
return dp[i][j];
let ans = Number.MAX_SAFE_INTEGER;
if (j == 0)
ans = Math.min(ans, recur(i + 1, j ^ 1, A, N) + A[i]);
if (j == 0 && i + 1 < N)
ans = Math.min(ans, recur(i + 2, j ^ 1, A, N) + A[i]
+ A[i + 1]);
if (j == 1)
ans = Math.min(ans, recur(i + 1, j ^ 1, A, N));
if (j == 1 && i + 1 < N)
ans = Math.min(ans, recur(i + 2, j ^ 1, A, N));
return dp[i][j] = ans;
}
function minCost( A, N)
{
for (let i=0; i<100001; i++)
for (let j=0; j<2; j++)
dp[i][j]=-1;
console.log(recur(0, 0, A, N)+ "<br>" );
}
let A = [ 1, 0, 1, 1, 0, 1, 1, 1 ];
let N = A.length;
minCost(A, N);
let A1 = [ 1, 1, 1, 1, 1, 1 ];
let N1 = A1.length;
minCost(A1, N1);
|
Complexity analysis:
The time complexity of the given recursive function is exponential, specifically O(2^N), where N is the size of the input array. This is because for each element in the array, we have two choices – either remove one element or remove two elements. Therefore, the number of recursive calls made is proportional to the number of possible ways we can remove elements from the array, which is 2 raised to the power of N.
The space complexity of the given function is O(N), as we are using a 2D array of size (N+1)x2 to store the intermediate results of the recursive calls. This is because for each element in the array, we need to store the minimum cost of emptying the array when starting from that element and making either an odd or even move. Therefore, the total number of entries in the 2D array is (N+1)x2.
Related Articles:
Last Updated :
28 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...