Open In App

POTD Solutions | 25 Oct’ 23 | Knapsack with Duplicate Items

Last Updated : 22 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

View all POTD Solutions

Welcome to the daily solutions of our PROBLEM OF THE DAY (POTD). We will discuss the entire problem step-by-step and work towards developing an optimized solution. This will not only help you brush up on your concepts of Dynamic Programming but will also help you build up problem-solving skills.

potd-25TH-BANNER

POTD 25 Oct’ 23

We recommend you to try this problem on our GeeksforGeeks Practice portal first, and maintain your streak to earn Geeksbits and other exciting prizes, before moving towards the solution.

POTD 25 October: Knapsack with Duplicate Items

Given a set of N items, each with a weight and a value, represented by the array w and val respectively. Also, a knapsack with weight limit W.
The task is to fill the knapsack in such a way that we can get the maximum profit. Return the maximum profit.
Note: Each item can be taken any number of times.

Example:

Input: W = 100
val[] = {1, 30}
wt[] = {1, 50}
Output: 100
There are many ways to fill knapsack.
1) 2 instances of 50 unit weight item.
2) 100 instances of 1 unit weight item.
3) 1 instance of 50 unit weight item and 50
instances of 1 unit weight items.
We get maximum value with option 2.

Input: W = 8
val[] = {10, 40, 50, 70}
wt[] = {1, 3, 4, 5}
Output: 110
We get maximum value with one unit of
weight 5 and one unit of weight 3.

Knapsack with Duplicate Item Using Dynamic Programming (Memoization):

Explores two choices at each step: including the current item if it doesn’t exceed the weight limit, or excluding it. The function uses a memoization table (‘dp’) to store and retrieve previously computed results to avoid redundant calculations. By recursively considering these choices and maximizing the total value, we find the optimal solution for the knapsack problem.

Below is the implantation of the above approach:

C++




class Solution {
public:
    // Recursive function to solve the 0/1 Knapsack problem
    int rec(int i, int sum, int N, int W, int val[],
            int wt[], vector<vector<int> >& dp)
    {
        // Base case: If we have processed all items (i ==
        // N), return 0.
        if (i == N)
            return 0;
  
        // If the result for the current item and remaining
        // capacity is already computed, return it.
        if (dp[i][sum] != -1)
            return dp[i][sum];
  
        int w = wt[i]; // Weight of the current item
        int v = val[i]; // Value of the current item
  
        int x = 0;
        int y = 0;
  
        // Check if we can include the current item in the
        // knapsack without exceeding its capacity
        if (w + sum <= W) {
            x = v
                + rec(i, sum + w, N, W, val, wt,
                      dp); // Include the current item
        }
  
        y = rec(i + 1, sum, N, W, val, wt,
                dp); // Exclude the current item
  
        // Calculate and store the maximum of including and
        // excluding the current item
        return dp[i][sum] = max(x, y);
    }
  
    // Function to solve the 0/1 Knapsack problem
    int knapSack(int N, int W, int val[], int wt[])
    {
        // Create a 2D DP array to memoize the results of
        // subproblems
        vector<vector<int> > dp(N, vector<int>(W + 1, -1));
  
        // Call the recursive function to find the maximum
        // value of items that can be included in the
        // knapsack
        return rec(0, 0, N, W, val, wt, dp);
    }
};


Java




class Solution {
    // Recursive function to calculate the maximum value for
    // the knapsack problem.
    static int rec(int i, int sum, int N, int W, int[] val,
                   int[] wt, int[][] dp)
    {
        // Base case: If all items have been considered,
        // return 0.
        if (i == N)
            return 0;
  
        // If the result for the current state (i, sum) has
        // already been calculated, return it.
        if (dp[i][sum] != -1)
            return dp[i][sum];
  
        int w = wt[i]; // Weight of the current item.
        int v = val[i]; // Value of the current item.
        int x = 0;
        int y = 0;
  
        // Check if the current item can be included in the
        // knapsack without exceeding its capacity.
        if (w + sum <= W) {
            // Include the current item and recursively
            // calculate the value.
            x = v + rec(i, sum + w, N, W, val, wt, dp);
        }
  
        // Exclude the current item and move to the next
        // item.
        y = rec(i + 1, sum, N, W, val, wt, dp);
  
        // Store the maximum value in dp array and return
        // it.
        return dp[i][sum] = Math.max(x, y);
    }
  
    // Wrapper function to initialize the DP array and start
    // the recursion.
    static int knapSack(int N, int W, int val[], int wt[])
    {
        int[][] dp = new int[N][W + 1];
  
        // Initialize the DP array with -1 to indicate that
        // no results have been calculated yet.
        for (int i = 0; i < N; i++) {
            Arrays.fill(dp[i], -1);
        }
  
        // Start the recursive calculation from the first
        // item with zero weight and zero value accumulated
        // so far.
        return rec(0, 0, N, W, val, wt, dp);
    }
}


Python3




class Solution:
    def rec(self, i, sum, N, W, val, wt, dp):
        # Base case: If we've processed all items (i == N), return 0.
        if i == N:
            return 0
  
        # If the result for this item and current sum is already calculated, return it.
        if dp[i][sum] != -1:
            return dp[i][sum]
  
        # Get the weight and value of the current item.
        w = wt[i]
        v = val[i]
  
        x = 0
        y = 0
  
        # Check if including the current item is possible (within weight limit).
        if w + sum <= W:
            # Calculate the maximum value if we include the current item.
            x = v + self.rec(i, sum + w, N, W, val, wt, dp)
  
        # Calculate the maximum value if we exclude the current item.
        y = self.rec(i + 1, sum, N, W, val, wt, dp)
  
        # Store the maximum of including and excluding the current item in the DP table.
        dp[i][sum] = max(x, y)
  
        return dp[i][sum]
  
    def knapSack(self, N, W, val, wt):
        # Initialize a DP table with -1 values to store computed results.
        dp = [[-1] * (W + 1) for _ in range(N)]
  
        # Call the recursive function to solve the 0/1 Knapsack problem.
        return self.rec(0, 0, N, W, val, wt, dp)


Time Complexity: O(N*W)
Auxiliary Space: O(N*W) 

Knapsack with Duplicate Items Using Tabulation Dynamic Programming:

Its an unbounded knapsack problem as we can use 1 or more instances of any resource. A simple 1D array, say dp[W+1] can be used such that dp[i] stores the maximum value which can achieved using all items with i capacity of knapsack. Note that we use 1D array here which is different from classical knapsack where we used 2D array. Here number of items never changes. We always have all items available.
We can compute dp[] using below formula:

dp[i] = 0
dp[i] = max(dp[i], dp[i-wt[j]] + val[j], where j varies from 0 to n-1 such that: wt[j] <= i

result = dp[W]

Below is the implementation of above approach. 

C++




class Solution {
public:
    int knapSack(int N, int W, int val[], int wt[])
    {
        // Create an array to store the maximum values for
        // different weights
        int dp[W + 1];
        memset(dp, 0, sizeof dp); // Initialize the dp array
                                  // with zeros
  
        // Fill dp[] using the bottom-up dynamic programming
        // approach
        for (int i = 0; i <= W; i++) {
            for (int j = 0; j < N; j++) {
                
                // Check if the weight of the current item
                // is less than or equal to the current
                // weight 'i'
                if (wt[j] <= i) {
                    
                    // Update dp[i] by choosing the maximum
                    // between its current value and the
                    // value of the current item plus the
                    // value obtained for the remaining
                    // weight after subtracting the weight
                    // of the current item
                    dp[i] = max(dp[i],
                                dp[i - wt[j]] + val[j]);
                }
            }
        }
  
        // The final element of the 'dp' array contains the
        // maximum value that can be obtained with the given
        // weight constraint 'W'
        return dp[W];
    }
};


Java




class Solution {
    static int knapSack(int N, int W, int val[], int wt[])
    {
        // Create an array 'dp' to store the maximum value
        // for each possible weight (from 0 to W).
        int[] dp = new int[W + 1];
  
        // Iterate through each weight from 0 to the maximum
        // weight 'W'.
        for (int i = 0; i <= W; i++) {
            // Iterate through each item (indexed by 'j') in
            // the list of items.
            for (int j = 0; j < N; j++) {
                // Check if the weight of the current item
                // is less than or equal to the current
                // weight 'i'.
                if (wt[j] <= i) {
                    // Calculate the maximum value that can
                    // be obtained by considering or not
                    // considering the current item.
                    dp[i] = Math.max(dp[i], dp[i - wt[j]]
                                                + val[j]);
                }
            }
        }
        // The final element of 'dp' contains the maximum
        // value achievable with a knapsack of weight 'W'.
        return dp[W];
    }
}


Python3




class Solution:
    def knapSack(self, N, W, val, wt):
        
        # Initialize a dynamic programming table 'dp' with zeros for values from 0 to W.
        dp = [0] * (W + 1)
  
        # Iterate over the capacity values from 0 to W.
        for i in range(W + 1):
  
            # Iterate over the items (N is the number of items).
            for j in range(N):
  
                # Check if the weight of the current item 'j' is less than or equal to the current capacity 'i'.
                if wt[j] <= i:
  
                    # Update 'dp[i]' by taking the maximum of the current value 'dp[i]' and
                    # the value of the current item plus the value of the subproblem for the remaining capacity.
                    dp[i] = max(dp[i], dp[i - wt[j]] + val[j])
  
        # Return the maximum value that can be achieved with the given capacity 'W'.
        return dp[W]


Time Complexity: O(N*W)
Auxiliary Space: O(N*W) 



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads