Given array p where p[i] is the price of ith item. The shop also offers bonuses on all items. If he buys the ith item he can get any f[i] items free of cost, the task is to return the minimum amount of money needed to buy n items.
Note: We won’t get [i] free items if the ith item has been received free of cost and not bought.
Examples:
Input: n = 4, p = {10, 20, 5, 3}, f = {2, 0, 1, 1}
Output: 8
Explanation: Will buy 3rd and 4th items and The week will get 1st and 2nd items free of cost because of the bonus that he got after buying 3rd and 4th items. So the answer is 8.Input: n = 3, p = {1, 10, 100}, f = {0, 0, 0}
Output: 111
Explanation: can’t get any free items. So he will have to pay for all the three items. So the answer is 111.
Approach: This can be solved with the following idea:
The problem can be solved using dynamic programming. The main idea is to consider each item and make a decision on whether to buy it or skip it while keeping track of the total cost. To minimize the cost, we should consider the bonuses provided for each item.
Below are the steps involved:
- Initialize a 2D array dp with dimensions 500×1001 to store the computed results of subproblems. dp[i][t+500] represents the minimum cost to buy the items starting from the i-th item when having a balance of t left after considering all bonuses.
-
Create a recursive function memo that takes the current item index i, remaining balance t, item prices array price, bonus items array time, and the total number of items n as parameters.
- If we have already considered all items (i >= n), return 0 if the remaining balance t is non-negative, indicating we have bought all items without overspending. Otherwise, return a large value (1e18) to indicate this is not a valid solution.
- If there are fewer items left to buy than there is a balance (n – i <= t), return 0 as there are no more items to buy, and the bonus doesn’t matter.
- Check if the result for the current state (i, t) is already computed and stored in the dp array. If so, return the stored result.
-
Recursively calculate the minimum cost by considering two options:
- Buy the current item i by reducing the balance by its price and adding the bonus items if available. Call memo for the next item (i+1) with the updated balance.
- Skip the current item i (i.e., don’t buy it) and reduce the balance by 1. Call memo for the next item (i+1) with the updated balance.
- Store the computed result in the dp array for the current state (i, t) to avoid recomputation and return the result.
- Initialize dp with -1 values to indicate that no results are computed yet.
- Call the memo function with initial parameters (0, 0, p, f, n) to find the minimum cost of buying n items.
Below is the implementation of the code:
// C++ code for the above approach: #include <bits/stdc++.h> using namespace std;
// Intializing a Dp long long dp[500][1001];
long long memo( int i, int t, vector< int >& price,
vector< int >& time , int n)
{ // If array end is reached
if (i >= n) {
if (t >= 0)
return 0;
return 1e18;
}
if (n - i <= t)
return 0;
// If values has already found
if (dp[i][t + 500] != -1)
return dp[i][t + 500];
// Get the value
return dp[i][t + 500]
= min(memo(i + 1, t + time [i], price, time , n)
+ price[i],
memo(i + 1, t - 1, price, time , n));
} // Function to calculate minimum money long long minCost( int n, vector< int >& p, vector< int >& f)
{ // Filling all values with 1
memset (dp, -1, sizeof (dp));
// Function to fill dp
return memo(0, 0, p, f, n);
} // Driver code int main()
{ int n = 4;
vector< int > p = { 10, 20, 5, 3 };
vector< int > f = { 2, 0, 1, 1 };
// Function call
cout << minCost(n, p, f);
return 0;
} |
import java.util.Arrays;
import java.util.Vector;
public class MinimumMoney {
// Initializing a Dp
static long [][] dp = new long [ 500 ][ 1001 ];
static long memo( int i, int t, Vector<Integer> price, Vector<Integer> time, int n) {
// If array end is reached
if (i >= n) {
if (t >= 0 )
return 0 ;
return ( long ) 1e18;
}
if (n - i <= t)
return 0 ;
// If values have already been found
if (dp[i][t + 500 ] != - 1 )
return dp[i][t + 500 ];
// Get the value
return dp[i][t + 500 ] = Math.min(memo(i + 1 , t + time.get(i), price, time, n) + price.get(i),
memo(i + 1 , t - 1 , price, time, n));
}
// Function to calculate minimum money
static long minCost( int n, Vector<Integer> p, Vector<Integer> f) {
// Filling all values with -1
for ( long [] row : dp) {
Arrays.fill(row, - 1 );
}
// Function to fill dp
return memo( 0 , 0 , p, f, n);
}
// Driver code
public static void main(String[] args) {
int n = 4 ;
Vector<Integer> p = new Vector<>(Arrays.asList( 10 , 20 , 5 , 3 ));
Vector<Integer> f = new Vector<>(Arrays.asList( 2 , 0 , 1 , 1 ));
// Function call
System.out.println(minCost(n, p, f));
}
} // This code is contributed by shivamgupta0987654321 |
# Initializing a DP dp = [[ - 1 ] * 1001 for _ in range ( 500 )]
def memo(i, t, price, time, n):
# If array end is reached
if i > = n:
if t > = 0 :
return 0
return float ( 'inf' )
if n - i < = t:
return 0
# If values have already been found
if dp[i][t + 500 ] ! = - 1 :
return dp[i][t + 500 ]
# Get the value
dp[i][t + 500 ] = min (memo(i + 1 , t + time[i], price, time, n) + price[i],
memo(i + 1 , t - 1 , price, time, n))
return dp[i][t + 500 ]
# Function to calculate minimum money def min_cost(n, p, f):
# Filling all values with 1
for i in range ( 500 ):
dp[i] = [ - 1 ] * 1001
# Function to fill dp
return memo( 0 , 0 , p, f, n)
# Driver code if __name__ = = "__main__" :
n = 4
p = [ 10 , 20 , 5 , 3 ]
f = [ 2 , 0 , 1 , 1 ]
# Function call
print (min_cost(n, p, f))
|
using System;
using System.Collections.Generic;
public class MinimumMoney
{ // Initializing a Dp
static long [,] dp = new long [500, 1001];
static long Memo( int i, int t, List< int > price, List< int > time, int n)
{
// If array end is reached
if (i >= n)
{
if (t >= 0)
return 0;
return ( long )1e18;
}
if (n - i <= t)
return 0;
// If values have already been found
if (dp[i, t + 500] != -1)
return dp[i, t + 500];
// Get the value
return dp[i, t + 500] = Math.Min(Memo(i + 1, t + time[i], price, time, n) + price[i],
Memo(i + 1, t - 1, price, time, n));
}
// Function to calculate minimum money
static long MinCost( int n, List< int > p, List< int > f)
{
// Filling all values with -1
for ( int i = 0; i < 500; i++)
{
for ( int j = 0; j < 1001; j++)
{
dp[i, j] = -1;
}
}
// Function to fill dp
return Memo(0, 0, p, f, n);
}
// Driver code
public static void Main( string [] args)
{
int n = 4;
List< int > p = new List< int > { 10, 20, 5, 3 };
List< int > f = new List< int > { 2, 0, 1, 1 };
// Function call
Console.WriteLine(MinCost(n, p, f)); // Output should be 8
}
} |
// Initializing a DP const dp = new Array(500).fill( null ).map(() => new Array(1001).fill(-1));
function memo(i, t, price, time, n) {
// If array end is reached
if (i >= n) {
if (t >= 0) {
return 0;
}
return Infinity;
}
if (n - i <= t) {
return 0;
}
// If values have already been found
if (dp[i][t + 500] !== -1) {
return dp[i][t + 500];
}
// Get the value
dp[i][t + 500] = Math.min(
memo(i + 1, t + time[i], price, time, n) + price[i],
memo(i + 1, t - 1, price, time, n)
);
return dp[i][t + 500];
} // Function to calculate minimum money function minCost(n, p, f) {
// Filling all values with 1
for (let i = 0; i < 500; i++) {
dp[i] = new Array(1001).fill(-1);
}
// Function to fill dp
return memo(0, 0, p, f, n);
} // Driver code const n = 4; const p = [10, 20, 5, 3]; const f = [2, 0, 1, 1]; // Function call console.log(minCost(n, p, f)); // This code is contributed by shivamgupta0987654321 |
8
Time Complexity: O(N)
Auxiliary Space: O(500 * 1001)