背包问题
01背包问题
首先要写出状态转移方程
i的编号从1开始
只装前i个物品,背包容量为c时背包能装的最大价值
dp[i,c] = Math.max( dp[i-1, c] , dp[i-1, c-wgt[i] ] + val[i])
判定边界条件
装的物品为0 ,即 i0 时dp为0
背包容量为0,即 c0 时dp为0
- 递归
/* 0-1 背包:记忆化搜索 */
function knapsackDFSMem(wgt, val, mem, i, c) {
// 若已选完所有物品或背包无剩余容量,则返回价值 0
if (i === 0 || c === 0) {
return 0;
}
// 若已有记录,则直接返回
if (mem[i][c] !== -1) {
return mem[i][c];
}
// 若超过背包容量,则只能选择不放入背包
if (wgt[i - 1] > c) {
return knapsackDFSMem(wgt, val, mem, i - 1, c);
}
// 计算不放入和放入物品 i 的最大价值
const no = knapsackDFSMem(wgt, val, mem, i - 1, c);
const yes =
knapsackDFSMem(wgt, val, mem, i - 1, c - wgt[i - 1]) + val[i - 1];
// 记录并返回两种方案中价值更大的那一个
mem[i][c] = Math.max(no, yes);
return mem[i][c];
}
- 动态规划
/* 0-1 背包:动态规划 */
function knapsackDP(wgt, val, cap) {
const n = wgt.length;
// 初始化 dp 表
const dp = Array(n + 1)
.fill(0)
.map(() => Array(cap + 1).fill(0));
// 状态转移
for (let i = 1; i <= n; i++) {
for (let c = 1; c <= cap; c++) {
if (wgt[i - 1] > c) {
// 若超过背包容量,则不选物品 i
dp[i][c] = dp[i - 1][c];
} else {
// 不选和选物品 i 这两种方案的较大值
dp[i][c] = Math.max(
dp[i - 1][c],
dp[i - 1][c - wgt[i - 1]] + val[i - 1]
);
}
}
}
return dp[n][cap];
}