Dynamic Programming学习笔记 (10) - 无限背包问题

334 阅读1分钟

无限背包问题与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];
    }
}