问题描述:对于每种物品,都具有两种不同的代价 c 1 [ i ] c_1[i] c1[i] 与 c 2 [ i ] c_2[i] c2[i];选择该物品必须同时付出这两种代价;对于每种代价都有一个可付出的最大值(上限)。问在每个物品只能使用一次的条件下,怎么选择物品(物品保持完整)可得到最大的价值。现有数据如下:
c1 = [2,3,4,5,6,7,8]; // 代价1
cap1 = 27; // 代价1的上限
c2 = [8,7,6,5,4,3,2]; // 代价2
cap2 = 31; // 代价2的上限
v = [3,4,5,6,7,8,9];
解题思路:令 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示前 i 中物品在代价1为 j,代价2为 k 的条件下装入背包的最大值。根据0-1背包问题有 d p [ i ] [ j ] [ k ] = m a x { d p [ i − 1 ] [ j ] [ k ] , d p [ i − 1 ] [ j − c 1 [ i ] ] [ k − c 2 [ i ] ] + v [ i ] } dp[i][j][k]=max\{dp[i-1][j][k],dp[i-1][j-c_1[i]][k-c_2[i]]+v[i]\} dp[i][j][k]=max{dp[i−1][j][k],dp[i−1][j−c1[i]][k−c2[i]]+v[i]}。存储结果的三位数组同样可以压缩一维,变成二维数组,即 d p [ j ] [ k ] = m a x { d p [ j ] [ k ] , d p [ j − c 1 [ i ] ] [ k − c 2 [ i ] ] + v [ i ] } dp[j][k]=max\{dp[j][k], dp[j-c_1[i]][k-c_2[i]]+v[i]\} dp[j][k]=max{dp[j][k],dp[j−c1[i]][k−c2[i]]+v[i]}。
public int knapsackProblem(int[] c1, int cap1, int[] c2, int cap2, int[] v) {
int[][] dp = new int[cap1 + 1][cap2 + 1];
for (int i = 0; i < c1.length; i++) {
for (int j = cap1; j >= c1[i]; j--) {
for (int k = cap2; k >= c2[i]; k--) {
dp[j][k] = Math.max(dp[j][k], dp[j - c1[i]][k - c2[i]] + v[i]);
}
}
}
return dp[cap1][cap2];
}
时间复杂度为 O ( n V 1 V 2 ) O(nV_1V_2) O(nV1V2),空间复杂度为 O ( V 1 V 2 ) O(V_1V_2) O(V1V2)。
上一篇:背包问题之混合背包问题
下一篇:背包问题之分组背包问题