Open In App

Minimum Cost with Bonus Items in Shopping

Last Updated : 31 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

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++




// 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;
}


Java




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


Python3




# 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))


C#




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
    }
}


Javascript




// 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


Output

8






Time Complexity: O(N)
Auxiliary Space: O(500 * 1001)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads