跳至主要內容

0-1背包问题

Mr.He大约 1 分钟

0-1背包问题

给你一个可装载重量为 W 的背包和 N 个物品,每个物品有重量和价值两个属性。其中第 i 个物品的重量为 wt[i],价值为 val[i]。现在让你用这个背包装物品,每个物品只能用一次,在不超过被包容量的前提下,最多能装的价值是多少?

N = 3, W = 4
wt = [2, 1, 3]
val = [4, 2, 3]

明确dp[i][w]定义

dp[i][w] 的定义如下:对于前 i 个物品,当前背包的容量为 w,这种情况下可以装的最大价值是 dp[i][w]

装 vs 不装

如果你没有把这第 i 个物品装入背包,那么很显然,最大价值 dp[i][w] 应该等于 dp[i-1][w],继承之前的结果。

如果你把这第 i 个物品装入了背包,那么 dp[i][w] 应该等于 val[i-1] + dp[i-1][w - wt[i-1]]

代码实现

/**
 * @param {number} W
 * @param {number} N
 * @param {number[]} wt
 * @param {number[]} val
 * @return {number}
 */
var knapsack = function(W, N, wt, val) {
    assert(N == wt.length);
    // 已初始化的base case
    var dp = new Array(N + 1).fill(0).map(() => new Array(W + 1).fill(0));
    for (var i = 1; i <= N; i++) {
        for (var w = 1; w <= W; w++) {
            if (w - wt[i - 1] < 0) {
                // 这种情况下只能选择不装入背包
                dp[i][w] = dp[i - 1][w];
            } else {
                // 装入或者不装入背包,择优
                dp[i][w] = Math.max(
                    dp[i - 1][w - wt[i-1]] + val[i-1], 
                    dp[i - 1][w]
                );
            }
        }
    }

    return dp[N][W];
};