📜  双背包|动态编程

📅  最后修改于: 2021-04-26 05:22:37             🧑  作者: Mango

给定一个包含’N’个不同项目的权重的数组’arr’,以及两个可以承受’W1’和’W2’权重的背包,任务是找到该数组’arr’的最大子集的总和,即可以放在两个背包中。不允许将任何物品一分为二,即应将一个物品作为一个整体放在一个袋子中。

例子:

解决方案:
递归解决方案是尝试填充两个背包的所有可能方式,然后选择重量最大的背包。
为了优化上述思路,我们需要确定DP的状态,并以此为基础建立解决方案。经过很少的观察,我们可以确定这可以用三种状态(i,w1_r,w2_r)表示。这里的“ i”表示我们要存储的元素的索引,w1_r表示第一个背包的剩余空间,w2_r表示第二个背包的剩余空间。因此,可以使用具有递归关系的3维动态编程来解决该问题。

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

上述递归关系的解释如下:

下面是上述方法的实现:

C++
// C++ implementation of the above approach
#include 
#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


输出:
13


时间复杂度:
O(N * W1 * W2)。