无限背包问题与0/1背包问题大致类似,不同之处在于可用物件的数量是无限的,其一般表述为给定一个背包,其承重为W,以及N种物件的重量和价值,每种物件都有无限的供应量可以放入背包,求背包中所有物件价值总和的最大值。
实例如下:
背包承重 W = 100
物件重量数组 weight = {1, 50}
物件价值数组 value = {1, 30}
可能的背包装填方式如下:
1)2个重50的物件,总价值 2 * 30 = 60
2) 100个重1的物件,总价值 1 * 100 = 100
3) 1个重50的物件和50个重1的物件,总价值 1 * 30 + 50 * 1 = 80
最大的可能值是第二种装填方式下的100
DP解题思路如下,给定一个背包承重k,我们可以使用如下的数学表达式
F(k)
= 0, k <= 0
= max of (
value[0] + F(k - weight[0]),
value[1] + F(k - weight[1]),
...
value[N - 1] + F(k - weight[N - 1])
)
这里F(k)返回的是背包承重为k时的最大价值和。当某个物件j可以放入背包(weight[j] <= k)的话,那么其价值和就是该物件的价值(value[j]) 加上背包承重为k - weight[j]时的最大价值和,依次选择每个物件后找到其中的最大值就是F(k)的返回值。
我们使用一个一维数组作为DP存储,其下标就是从0到W的各个数字,依照上面的表达式从小到大依次计算DP数组的每个元素,最后DP[W]中的数值就是问题的最终答案。
Java代码如下
class Solution {
public int unboundedKnapsack(int[] weight, int[] value, int W) {
int N = value.length;
int[] dp = new int[W + 1];
for (int k = 1; k <= W; k ++) {
int maxValue = 0;
for (int j = 0; j < N; j ++) {
int w = weight[j];
if (k >= w) {
int v = value[j] + dp[k - w];
maxValue = Math.max(maxValue, v);
}
}
dp[k] = maxValue;
}
return dp[W];
}
}