Saturday, November 16, 2024
Google search engine
HomeLanguagesDynamic ProgrammingDouble Knapsack | Dynamic Programming

Double Knapsack | Dynamic Programming

Given an array ‘arr’ containing the weight of ‘N’ distinct items, and two knapsacks that can withstand ‘W1’ and ‘W2’ weights, the task is to find the sum of the largest subset of the array ‘arr’, that can be fit in the two knapsacks. It’s not allowed to break any items in two, i.e an item should be put in one of the bags as a whole.
Examples: 
 

Input : arr[] = {8, 3, 2} 
W1 = 10, W2 = 3 
Output : 13 
First and third objects go in the first knapsack. The second object goes in the second knapsack. Thus, the total weight becomes 13.
Input : arr[] = {8, 5, 3} 
W1 = 10, W2 = 3 
Output : 11 
 

 

Solution: 
A recursive solution is to try out all the possible ways of filling the two knapsacks and choose the one giving the maximum weight. 
To optimize the above idea, we need to determine the states of DP, that we will build up our solution upon. After little observation, we can determine that this can be represented in three states (i, w1_r, w2_r). Here ‘i’ means the index of the element we are trying to store, w1_r means the remaining space of the first knapsack, and w2_r means the remaining space of the second knapsack. Thus, the problem can be solved using a 3-dimensional dynamic-programming with a recurrence relation 
 

DP[i][w1_r][w2_r] = max( DP[i + 1][w1_r][w2_r],
arr[i] + DP[i + 1][w1_r - arr[i]][w2_r],
arr[i] + DP[i + 1][w1_r][w2_r - arr[i]])

The explanation for the above recurrence relation is as follows: 
 

For each ‘i’, we can either: 
 

  1. Don’t select the item ‘i’.
  2. Fill the item ‘i’ in first knapsack.
  3. Fill the item ‘i’ in second knapsack.

Below is the implementation of the above approach:
 

C++




// C++ implementation of the above approach
#include <bits/stdc++.h>
#define maxN 31
#define maxW 31
using namespace std;
 
// 3D array to store
// states of DP
int dp[maxN][maxW][maxW];
 
// w1_r represents remaining capacity of 1st knapsack
// w2_r represents remaining capacity of 2nd knapsack
// i represents index of the array arr we are working on
int maxWeight(int* arr, int n, int w1_r, int w2_r, int i)
{
    // Base case
    if (i == n)
        return 0;
    if (dp[i][w1_r][w2_r] != -1)
        return dp[i][w1_r][w2_r];
 
    // Variables to store the result of three
    // parts of recurrence relation
    int fill_w1 = 0, fill_w2 = 0, fill_none = 0;
 
    if (w1_r >= arr[i])
        fill_w1 = arr[i] +
         maxWeight(arr, n, w1_r - arr[i], w2_r, i + 1);
 
    if (w2_r >= arr[i])
        fill_w2 = arr[i] +
         maxWeight(arr, n, w1_r, w2_r - arr[i], i + 1);
 
    fill_none = maxWeight(arr, n, w1_r, w2_r, i + 1);
 
    // Store the state in the 3D array
    dp[i][w1_r][w2_r] = max(fill_none, max(fill_w1, fill_w2));
 
    return dp[i][w1_r][w2_r];
}
 
// Driver code
int main()
{
    // Input array
    int arr[] = { 8, 2, 3 };
 
    // Initializing the array with -1
    memset(dp, -1, sizeof(dp));
 
    // Number of elements in the array
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Capacity of knapsacks
    int w1 = 10, w2 = 3;
 
    // Function to be called
    cout << maxWeight(arr, n, w1, w2, 0);
    return 0;
}


Java




// Java implementation of the above approach
 
class GFG
{
    static int maxN = 31;
    static int maxW = 31;
 
    // 3D array to store
    // states of DP
    static int dp [][][] = new int[maxN][maxW][maxW];
     
    // w1_r represents remaining capacity of 1st knapsack
    // w2_r represents remaining capacity of 2nd knapsack
    // i represents index of the array arr we are working on
    static int maxWeight(int arr [] , int n, int w1_r, int w2_r, int i)
    {
        // Base case
        if (i == n)
            return 0;
        if (dp[i][w1_r][w2_r] != -1)
            return dp[i][w1_r][w2_r];
     
        // Variables to store the result of three
        // parts of recurrence relation
        int fill_w1 = 0, fill_w2 = 0, fill_none = 0;
     
        if (w1_r >= arr[i])
            fill_w1 = arr[i] +
            maxWeight(arr, n, w1_r - arr[i], w2_r, i + 1);
     
        if (w2_r >= arr[i])
            fill_w2 = arr[i] +
            maxWeight(arr, n, w1_r, w2_r - arr[i], i + 1);
     
        fill_none = maxWeight(arr, n, w1_r, w2_r, i + 1);
     
        // Store the state in the 3D array
        dp[i][w1_r][w2_r] = Math.max(fill_none, Math.max(fill_w1, fill_w2));
     
        return dp[i][w1_r][w2_r];
    }
     
    // Driver code
    public static void main (String[] args)
    {
     
        // Input array
        int arr[] = { 8, 2, 3 };
     
        // Initializing the array with -1
         
        for (int i = 0; i < maxN ; i++)
            for (int j = 0; j < maxW ; j++)
                for (int k = 0; k < maxW ; k++)
                        dp[i][j][k] = -1;
         
        // Number of elements in the array
        int n = arr.length;
     
        // Capacity of knapsacks
        int w1 = 10, w2 = 3;
     
        // Function to be called
        System.out.println(maxWeight(arr, n, w1, w2, 0));
    }
}
 
// This code is contributed by ihritik


Python3




# Python3 implementation of the above approach
 
# w1_r represents remaining capacity of 1st knapsack
# w2_r represents remaining capacity of 2nd knapsack
# i represents index of the array arr we are working on
def maxWeight(arr, n, w1_r, w2_r, i):
 
    # Base case
    if i == n:
        return 0
    if dp[i][w1_r][w2_r] != -1:
        return dp[i][w1_r][w2_r]
 
    # Variables to store the result of three
    # parts of recurrence relation
    fill_w1, fill_w2, fill_none = 0, 0, 0
 
    if w1_r >= arr[i]:
        fill_w1 = arr[i] + maxWeight(arr, n, w1_r - arr[i],
                                             w2_r, i + 1)
 
    if w2_r >= arr[i]:
        fill_w2 = arr[i] + maxWeight(arr, n, w1_r,
                                     w2_r - arr[i], i + 1)
 
    fill_none = maxWeight(arr, n, w1_r, w2_r, i + 1)
 
    # Store the state in the 3D array
    dp[i][w1_r][w2_r] = max(fill_none, max(fill_w1,
                                           fill_w2))
 
    return dp[i][w1_r][w2_r]
 
 
# Driver code
if __name__ == "__main__":
 
    # Input array
    arr = [8, 2, 3]
    maxN, maxW = 31, 31
     
    # 3D array to store
    # states of DP
    dp = [[[-1] * maxW] * maxW] * maxN
     
    # Number of elements in the array
    n = len(arr)
 
    # Capacity of knapsacks
    w1, w2 = 10, 3
 
    # Function to be called
    print(maxWeight(arr, n, w1, w2, 0))
     
# This code is contributed by Rituraj Jain


C#




// C# implementation of the above approach
using System;
 
class GFG
{
    static int maxN = 31;
    static int maxW = 31;
 
    // 3D array to store
    // states of DP
    static int [ , , ] dp = new int[maxN, maxW, maxW];
     
    // w1_r represents remaining capacity of 1st knapsack
    // w2_r represents remaining capacity of 2nd knapsack
    // i represents index of the array arr we are working on
    static int maxWeight(int [] arr, int n, int w1_r,
                                    int w2_r, int i)
    {
        // Base case
        if (i == n)
            return 0;
        if (dp[i ,w1_r, w2_r] != -1)
            return dp[i, w1_r, w2_r];
     
        // Variables to store the result of three
        // parts of recurrence relation
        int fill_w1 = 0, fill_w2 = 0, fill_none = 0;
     
        if (w1_r >= arr[i])
            fill_w1 = arr[i] +
            maxWeight(arr, n, w1_r - arr[i], w2_r, i + 1);
     
        if (w2_r >= arr[i])
            fill_w2 = arr[i] +
            maxWeight(arr, n, w1_r, w2_r - arr[i], i + 1);
     
        fill_none = maxWeight(arr, n, w1_r, w2_r, i + 1);
     
        // Store the state in the 3D array
        dp[i, w1_r, w2_r] = Math.Max(fill_none, Math.Max(fill_w1, fill_w2));
     
        return dp[i, w1_r, w2_r];
    }
     
    // Driver code
    public static void Main ()
    {
     
        // Input array
        int [] arr = { 8, 2, 3 };
     
        // Initializing the array with -1
         
        for (int i = 0; i < maxN ; i++)
            for (int j = 0; j < maxW ; j++)
                for (int k = 0; k < maxW ; k++)
                        dp[i, j, k] = -1;
         
        // Number of elements in the array
        int n = arr.Length;
     
        // Capacity of knapsacks
        int w1 = 10, w2 = 3;
     
        // Function to be called
        Console.WriteLine(maxWeight(arr, n, w1, w2, 0));
    }
}
 
// This code is contributed by ihritik


Javascript




<script>
 
// Javascript implementation of
// the above approach
 
var maxN = 31
var maxW = 31
 
// 3D array to store
// states of DP
var dp = Array(maxN);
 
for(var i=0;i<maxN;i++)
{
    dp[i] = Array(maxW);
    for(var j =0; j<maxW; j++)
    {
        dp[i][j] = Array(maxW).fill(-1);
    }
}
 
// w1_r represents remaining
// capacity of 1st knapsack
// w2_r represents remaining
// capacity of 2nd knapsack
// i represents index of the array arr
// we are working on
function maxWeight(arr, n, w1_r, w2_r, i)
{
    // Base case
    if (i == n)
        return 0;
    if (dp[i][w1_r][w2_r] != -1)
        return dp[i][w1_r][w2_r];
 
    // Variables to store the result of three
    // parts of recurrence relation
    var fill_w1 = 0, fill_w2 = 0, fill_none = 0;
 
    if (w1_r >= arr[i])
        fill_w1 = arr[i] +
         maxWeight(arr, n, w1_r - arr[i],
         w2_r, i + 1);
 
    if (w2_r >= arr[i])
        fill_w2 = arr[i] +
         maxWeight(arr, n, w1_r, w2_r -
         arr[i], i + 1);
 
    fill_none = maxWeight(arr, n, w1_r,
    w2_r, i + 1);
 
    // Store the state in the 3D array
    dp[i][w1_r][w2_r] = Math.max(fill_none,
    Math.max(fill_w1, fill_w2));
 
    return dp[i][w1_r][w2_r];
}
 
// Driver code
// Input array
var arr = [8, 2, 3 ];
 
// Number of elements in the array
var n = arr.length;
 
// Capacity of knapsacks
var w1 = 10, w2 = 3;
 
// Function to be called
document.write( maxWeight(arr, n, w1, w2, 0));
 
</script>


Output

13



Time complexity: O(N*W1*W2)
Auxiliary Space: O(N*W1*W2))

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 3-D DP to store the solution of the subproblems.
  • Initialize the DP with base cases if (i == 0) then dp[i][w1_r][w2_r] = 0
  • Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
  • Return the final solution stored in return dp[n][w1][w2].

Implementation :

C++




// C++ implementation of the tabulation approach
#include <bits/stdc++.h>
#define maxN 31
#define maxW 31
using namespace std;
 
// 3D array to store
// states of DP
int dp[maxN][maxW][maxW];
 
// Function to calculate
// maximum weight that can be put
// into the knapsacks
int maxWeight(int* arr, int n, int w1, int w2)
{
    // Iterate over all possible states
    for (int i = 0; i <= n; i++)
    {
        for (int w1_r = 0; w1_r <= w1; w1_r++)
        {
            for (int w2_r = 0; w2_r <= w2; w2_r++)
            {
            // Base case   
            if (i == 0)
            dp[i][w1_r][w2_r] = 0;
            // If the current item can be put in
            // the first knapsack
            else if (arr[i - 1] <= w1_r && arr[i - 1] <= w2_r)
                dp[i][w1_r][w2_r] =
                max(arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                    max(arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                        dp[i - 1][w1_r][w2_r]));
 
            // If the current item can be put in
            // the second knapsack
            else if (arr[i - 1] <= w2_r)
                dp[i][w1_r][w2_r] = max(arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                                    dp[i - 1][w1_r][w2_r]);
 
            // If the current item can be put in
            // the first knapsack
            else if (arr[i - 1] <= w1_r)
                dp[i][w1_r][w2_r] = max(arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                                    dp[i - 1][w1_r][w2_r]);
 
            // If the current item can not be put in
            // either of the knapsacks
            else
                dp[i][w1_r][w2_r] = dp[i - 1][w1_r][w2_r];
            }
        }
    }
     
    // Return the maximum weight that can be put
    // into the knapsacks
    return dp[n][w1][w2];
}
 
// Driver code
int main()
{
    // Input array
    int arr[] = { 8, 2, 3 };
    // Number of elements in the array
    int n = sizeof(arr) / sizeof(arr[0]);
     
    // Capacity of knapsacks
    int w1 = 10, w2 = 3;
     
    // Function to be called
    cout << maxWeight(arr, n, w1, w2);
    return 0;
}


Java




import java.util.*;
 
public class Main
{
   
    // 3D array to store states of DP
    static int[][][] dp = new int[31][31][31];
 
    // Function to calculate maximum weight
  // that can be put into the knapsacks
    public static int maxWeight(int[] arr, int n,
                                int w1, int w2)
    {
       
        // Iterate over all possible states
        for (int i = 0; i <= n; i++) {
            for (int w1_r = 0; w1_r <= w1; w1_r++) {
                for (int w2_r = 0; w2_r <= w2; w2_r++) {
                    // Base case
                    if (i == 0) {
                        dp[i][w1_r][w2_r] = 0;
                    }
                   
                    // If the current item can be put in the first knapsack
                    else if (arr[i - 1] <= w1_r && arr[i - 1] <= w2_r) {
                        dp[i][w1_r][w2_r] = Math.max(
                                arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                                Math.max(arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]], dp[i - 1][w1_r][w2_r]));
                    }
                   
                    // If the current item can be put in the second knapsack
                    else if (arr[i - 1] <= w2_r) {
                        dp[i][w1_r][w2_r] = Math.max(arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                                dp[i - 1][w1_r][w2_r]);
                    }
                   
                    // If the current item can be put in the first knapsack
                    else if (arr[i - 1] <= w1_r) {
                        dp[i][w1_r][w2_r] = Math.max(arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                                dp[i - 1][w1_r][w2_r]);
                    }
                   
                    // If the current item can not be put in either of the knapsacks
                    else {
                        dp[i][w1_r][w2_r] = dp[i - 1][w1_r][w2_r];
                    }
                }
            }
        }
 
        // Return the maximum weight that can be put into the knapsacks
        return dp[n][w1][w2];
    }
 
    // Driver code
    public static void main(String[] args)
    {
       
        // Input array
        int[] arr = { 8, 2, 3 };
       
        // Number of elements in the array
        int n = arr.length;
 
        // Capacity of knapsacks
        int w1 = 10, w2 = 3;
 
        // Function to be called
        System.out.println(maxWeight(arr, n, w1, w2));
    }
}


Python3




# Constants for maximum values
maxN = 31
maxW = 31
 
# 3D array to store states of DP
dp = [[[0 for _ in range(maxW)] for _ in range(maxW)] for _ in range(maxN)]
 
# Function to calculate maximum weight that can be put into the knapsacks
def maxWeight(arr, n, w1, w2):
    # Iterate over all possible states
    for i in range(n + 1):
        for w1_r in range(w1 + 1):
            for w2_r in range(w2 + 1):
                # Base case
                if i == 0:
                    dp[i][w1_r][w2_r] = 0
                # If the current item can be put in both knapsacks
                elif arr[i - 1] <= w1_r and arr[i - 1] <= w2_r:
                    dp[i][w1_r][w2_r] = max(
                        arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                        max(
                            arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                            dp[i - 1][w1_r][w2_r]
                        )
                    )
                # If the current item can be put in the second knapsack
                elif arr[i - 1] <= w2_r:
                    dp[i][w1_r][w2_r] = max(
                        arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                        dp[i - 1][w1_r][w2_r]
                    )
                # If the current item can be put in the first knapsack
                elif arr[i - 1] <= w1_r:
                    dp[i][w1_r][w2_r] = max(
                        arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                        dp[i - 1][w1_r][w2_r]
                    )
                # If the current item cannot be put in either knapsack
                else:
                    dp[i][w1_r][w2_r] = dp[i - 1][w1_r][w2_r]
 
    # Return the maximum weight that can be put into the knapsacks
    return dp[n][w1][w2]
 
# Driver code
if __name__ == "__main__":
    # Input array
    arr = [8, 2, 3]
    # Number of elements in the array
    n = len(arr)
 
    # Capacity of knapsacks
    w1 = 10
    w2 = 3
 
    # Function call
    print(maxWeight(arr, n, w1, w2))


C#




using System;
 
public class KnapsackProblem
{
    // Function to calculate
    // maximum weight that can be put
    // into the knapsacks
    public static int MaxWeight(int[] arr, int n, int w1, int w2)
    {
        // 3D array to store
        // states of DP
        int[,,] dp = new int[n + 1, w1 + 1, w2 + 1];
 
        // Iterate over all possible states
        for (int i = 0; i <= n; i++)
        {
            for (int w1_r = 0; w1_r <= w1; w1_r++)
            {
                for (int w2_r = 0; w2_r <= w2; w2_r++)
                {
                    // Base case   
                    if (i == 0)
                        dp[i, w1_r, w2_r] = 0;
 
                    // If the current item can be put in
                    // the first knapsack
                    else if (arr[i - 1] <= w1_r && arr[i - 1] <= w2_r)
                        dp[i, w1_r, w2_r] =
                            Math.Max(arr[i - 1] + dp[i - 1, w1_r - arr[i - 1], w2_r],
                                     Math.Max(arr[i - 1] + dp[i - 1, w1_r, w2_r - arr[i - 1]],
                                              dp[i - 1, w1_r, w2_r]));
 
                    // If the current item can be put in
                    // the second knapsack
                    else if (arr[i - 1] <= w2_r)
                        dp[i, w1_r, w2_r] = Math.Max(arr[i - 1] + dp[i - 1, w1_r, w2_r - arr[i - 1]],
                                                      dp[i - 1, w1_r, w2_r]);
 
                    // If the current item can be put in
                    // the first knapsack
                    else if (arr[i - 1] <= w1_r)
                        dp[i, w1_r, w2_r] = Math.Max(arr[i - 1] + dp[i - 1, w1_r - arr[i - 1], w2_r],
                                                      dp[i - 1, w1_r, w2_r]);
 
                    // If the current item can not be put in
                    // either of the knapsacks
                    else
                        dp[i, w1_r, w2_r] = dp[i - 1, w1_r, w2_r];
                }
            }
        }
 
        // Return the maximum weight that can be put
        // into the knapsacks
        return dp[n, w1, w2];
    }
 
    // Driver code
    public static void Main()
    {
        // Input array
        int[] arr = { 8, 2, 3 };
        // Number of elements in the array
        int n = arr.Length;
 
        // Capacity of knapsacks
        int w1 = 10, w2 = 3;
 
        // Function to be called
        Console.WriteLine(MaxWeight(arr, n, w1, w2));
    }
}


Javascript




const maxN = 31;
const maxW = 31;
 
// 3D array to store states of DP
const dp = new Array(maxN).fill(null).map(() =>
           new Array(maxW).fill(null).map(() =>
           new Array(maxW).fill(0)));
 
// Function to calculate maximum weight that can be put into the knapsacks
function maxWeight(arr, n, w1, w2) {
    // Iterate over all possible states
    for (let i = 0; i <= n; i++) {
        for (let w1_r = 0; w1_r <= w1; w1_r++) {
            for (let w2_r = 0; w2_r <= w2; w2_r++) {
             
                // Base case
                if (i === 0)
                {
                    dp[i][w1_r][w2_r] = 0;
                }
                else if (arr[i - 1] <= w1_r && arr[i - 1] <= w2_r)
                {
                    dp[i][w1_r][w2_r] =
                        Math.max(
                            arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                            Math.max(
                                arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                                dp[i - 1][w1_r][w2_r]
                            )
                        );
                }
                else if (arr[i - 1] <= w2_r)
                {
                    dp[i][w1_r][w2_r] = Math.max(
                        arr[i - 1] + dp[i - 1][w1_r][w2_r - arr[i - 1]],
                        dp[i - 1][w1_r][w2_r]
                    );
                }
                else if (arr[i - 1] <= w1_r)
                {
                    dp[i][w1_r][w2_r] = Math.max(
                        arr[i - 1] + dp[i - 1][w1_r - arr[i - 1]][w2_r],
                        dp[i - 1][w1_r][w2_r]
                    );
                }
                else
                {
                    dp[i][w1_r][w2_r] = dp[i - 1][w1_r][w2_r];
                }
            }
        }
    }
 
    // Return the maximum weight that can be put into the knapsacks
    return dp[n][w1][w2];
}
 
// Driver code
 
// Input array
const arr = [8, 2, 3];
     
// Number of elements in the array
const n = arr.length;
 
// Capacity of knapsacks
const w1 = 10, w2 = 3;
 
// Function to be called
console.log(maxWeight(arr, n, w1, w2));


Output

13

Time complexity: O(N*W1*W2)
Auxiliary Space: O(N*W1*W2))

Feeling lost in the world of random DSA topics, wasting time without progress? It’s time for a change! Join our DSA course, where we’ll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments