给定N个项目,每个项目都具有给定的权重C i和利润值P i ,任务是通过选择最多K个项目和最大权重W来最大化利润。
例子:
Input: N = 5, P[] = {2, 7, 1, 5, 3}, C[] = {2, 5, 2, 3, 4}, W = 8, K = 2.
Output: 12
Explanation:
Here, the maximum possible profit is when we take 2 items: item2 (P[1] = 7 and C[1] = 5) and item4 (P[3] = 5 and C[3] = 3).
Hence, maximum profit = 7 + 5 = 12
Input: N = 5, P[] = {2, 7, 1, 5, 3}, C[] = {2, 5, 2, 3, 4}, W = 1, K = 2
Output: 0
Explanation: All weights are greater than 1. Hence, no item can be picked.
方法:动态编程方法比一般递归方法更可取。让我们首先验证DP的条件是否仍然满足。
- 子问题重叠:尝试递归解时,首先添加1项,并且解集为(1),(2),…(n)。在第二个迭代中,我们有(1,2),依此类推,其中重新计算了(1)和(2)。因此,将有重叠的解决方案。
- 最佳子结构:总的来说,每个项目只有两个选择,可以包含在解决方案中,也可以拒绝。对于z元素的特定子集,第(z + 1)个元素的解可以具有与z个元素相对应的解,或者如果第(z + 1)个元素不超过背包约束,则可以添加第(z + 1)个元素。无论哪种方式,都可以满足最佳的子结构特性。
让我们得出递归。让我们考虑一个3维表dp [N] [W] [K] ,其中N是元素数, W是最大承重量, K是背包中允许的最大物品数。让我们定义一个状态dp [i] [j] [k] ,其中i表示我们正在考虑第i个元素, j表示当前填充的权重, k表示到目前为止填充的项数。
对于每个状态dp [i] [j] [k] ,利润要么是前一状态的利润(当不包括当前状态时),要么是当前项目的利润加到前一状态的利润(当当前状态时)项目被选中)。因此,递归关系为:
dp[i][j][k] = max( dp[i-1][j][k], dp[i-1][j-W[i-1]][k-1] + P[i])
下面是上述方法的实现:
C++
// C++ code for the extended
// Knapsack Approach
#include
using namespace std;
// To store the dp values
int dp[100][100][100];
int maxProfit(int profit[],
int weight[],
int n, int max_W,
int max_E)
{
// for each element given
for (int i = 1; i <= n; i++)
{
// For each possible
// weight value
for (int j = 1; j <= max_W; j++)
{
// For each case where
// the total elements are
// less than the constraint
for (int k = 1; k <= max_E; k++)
{
// To ensure that we dont
// go out of the array
if (j >= weight[i-1])
{
dp[i][j][k]
= max(dp[i - 1][j][k],
dp[i - 1][j -
weight[i-1]][k - 1]+
profit[i-1]);
}
else
{
dp[i][j][k]
= dp[i - 1][j][k];
}
}
}
}
return dp[n][max_W][max_E];
}
// Driver Code
int main()
{
memset(dp, 0, sizeof(dp));
int n = 5;
int profit[] = { 2, 7, 1, 5, 3 };
int weight[] = { 2, 5, 2, 3, 4 };
int max_weight = 8;
int max_element = 2;
cout << maxProfit(profit,
weight, n,
max_weight,
max_element)
<< "\n";
return 0;
}
Java
// Java code for the extended
// Knapsack Approach
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG{
// To store the dp values
static int[][][] dp = new int[100][100][100];
static int maxProfit(int profit[],
int weight[],
int n, int max_W,
int max_E)
{
// for each element given
for(int i = 1; i <= n; i++)
{
// For each possible
// weight value
for(int j = 1; j <= max_W; j++)
{
// For each case where
// the total elements are
// less than the constraint
for(int k = 1; k <= max_E; k++)
{
// To ensure that we dont
// go out of the array
if (j >= weight[i - 1])
{
dp[i][j][k] = Math.max(dp[i - 1][j][k],
dp[i - 1][j -
weight[i - 1]][k - 1] +
profit[i - 1]);
}
else
{
dp[i][j][k] = dp[i - 1][j][k];
}
}
}
}
return dp[n][max_W][max_E];
}
// Driver code
public static void main(String[] args)
{
int n = 5;
int profit[] = { 2, 7, 1, 5, 3 };
int weight[] = { 2, 5, 2, 3, 4 };
int max_weight = 8;
int max_element = 2;
System.out.println(maxProfit(profit,
weight, n,
max_weight,
max_element));
}
}
// This code is contributed by offbeat
12
时间复杂度: O(N * W * K)
辅助空间: O(N * W * K)