用填充表格法吃透01背包及其变形-2

2.3 步骤3:dp数组如何初始化

初始化逻辑与二维一致:容量为0时,最大价值为0,因此dp[0] = 0;其他容量的初始值也为0(因为初始无物品可放,最大价值为0),即dp = new Array(capacity + 1).fill(0)。

初始化后的单行表格:0,0,0,0,0,0,0,0,0(j从0到8)

2.4 步骤4:确定遍历顺序(表格填充顺序)

一维DP的遍历顺序有严格要求,核心是「倒序遍历容量」,对应单行表格的「从右往左填充」------明确单行表格的填充顺序是避免重复选择物品的关键:

  1. 必须先遍历物品,再遍历容量:逐个处理每个物品,每次处理时更新整个单行表格(覆盖上一行结果);

  2. 容量必须倒序遍历(j从C到weightsi-1) :从最大容量往小容量填充,确保计算dp[j]时,dp[j - weights[i-1]]仍是上一行(未处理当前物品)的旧值,避免同一物品被多次选择。

关键原因:一维DP的核心是用单行表格复用二维表格的空间,表格中每个位置的数值都依赖"上一轮未更新的旧值"(对应二维的dp[i-1][j - w[i]])。若正序遍历容量,dp[j - w[i]]会被提前更新(相当于二维的dp[i][j - w[i]]),导致同一个物品被多次选择(变成完全背包);倒序遍历能保证计算dp[j]时,dp[j - w[i]]仍是上一行(未选当前物品)的结果,对应单行表格从右往左填充,完美契合01背包「每个物品选一次」的规则。

反例(正序遍历容量):若j从weightsi-1到C正序遍历,处理物品1(w=2,v=3)时,j=2会更新dp2=3,j=4时会用到dp2的新值(3),计算dp4 = dp4 + 3 = 3,相当于把物品1放入了两次,违背01背包规则。

2.5 步骤5:打印dp数组(验证)

通过打印单行表格的滚动更新过程,验证填充规则的正确性。仍用测试用例 weights = [2,3,4,5]、values = [3,4,5,6]、capacity = 8,演示一维DP数组(单行表格)的填充变化:

  1. 初始状态:dp = 0,0,0,0,0,0,0,0,0

  2. 处理物品1(w=2,v=3),j从8到2倒序:

    更新后:dp = 0,0,3,3,3,3,3,3,3

    • j=8:dp8 = max(0, dp8-2+3) = max(0,0+3)=3;

    • j=7:dp7 = max(0, dp5+3)=3;

    • ...(j=2到6同理);

    • j=2:dp2 = max(0, dp0+3)=3;

  3. 处理物品2(w=3,v=4),j从8到3倒序:

    更新后:dp = 0,0,3,4,4,7,7,7,7

    • j=8:max(3, dp5+4)=max(3,3+4)=7;

    • j=7:max(3, dp4+4)=max(3,3+4)=7;

    • j=6:max(3, dp3+4)=max(3,3+4)=7;

    • j=5:max(3, dp2+4)=max(3,3+4)=7;

    • j=4:max(3, dp1+4)=max(3,0+4)=4;

    • j=3:max(3, dp0+4)=max(3,0+4)=4;

  4. 处理物品3(w=4,v=5),j从8到4倒序:

    更新后:dp = 0,0,3,4,5,5,8,9,9

    • j=8:max(7, dp4+5)=max(7,4+5)=9;

    • j=7:max(7, dp3+5)=max(7,4+5)=9;

    • j=6:max(7, dp2+5)=max(7,3+5)=8;

    • j=5:max(7, dp1+5)=max(7,0+5)=7;

    • j=4:max(4, dp0+5)=max(4,0+5)=5;

  5. 处理物品4(w=5,v=6),j从8到5倒序:

    更新后:dp = 0,0,3,4,5,6,8,9,10

    • j=8:max(9, dp3+6)=max(9,4+6)=10;

    • j=7:max(9, dp2+6)=max(9,3+6)=9;

    • j=6:max(8, dp1+6)=max(8,0+6)=8;

    • j=5:max(5, dp0+6)=max(5,0+6)=6;

最终单行表格dp[8] = 10,与二维DP结果一致,验证了优化的正确性。

2.6 一维DP空间优化完整代码(JavaScript)

javascript 复制代码
/**
 * 基础01背包(一维DP空间优化解法)
 * @param {number[]} weights - 物品重量数组
 * @param {number[]} values - 物品价值数组
 * @param {number} capacity - 背包最大容量
 * @returns {number} - 背包能容纳的最大价值
 */
function knapsack_1d(weights, values, capacity) {
  const n = weights.length;
  // 1. 初始化一维dp数组:dp[j]表示容量j的背包的最大价值,初始值0
  const dp = new Array(capacity + 1).fill(0);

  // 2. 遍历顺序:先遍历物品(i从0到n-1),再倒序遍历容量(j从capacity到weights[i])(从右往左填充)
  for (let i = 0; i < n; i++) {
    // 倒序遍历避免重复选择当前物品
    for (let j = capacity; j >= weights[i]; j--) {
      // 3. 递推公式:不选当前物品的最大价值 vs 选当前物品的最大价值
      dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);
    }
    // 打印每次处理物品后的dp数组(单行表格更新过程)
    console.log(`处理完物品${i + 1}后,dp数组:`, [...dp]);
  }

  // 最终答案:容量为capacity的背包的最大价值
  return dp[capacity];
}

// 测试用例
const weights1 = [2, 3, 4, 5];
const values1 = [3, 4, 5, 6];
const capacity1 = 8;
console.log('最大价值:', knapsack_1d(weights1, values1, capacity1)); // 输出:10
相关推荐
纪念 22923 分钟前
C++算法(一)
开发语言·c++·算法
程序猿乐锅27 分钟前
【黑马点评 | 第九篇】秒杀优化-异步实现
java·spring boot·redis·后端·spring·中间件·mybatis
Wx-bishekaifayuan36 分钟前
springboot户外登山社交小程序19787-计算机课程设计、毕业设计
spring boot·后端·python·spring·elasticsearch·django·课程设计
+VX:Fegn089540 分钟前
计算机毕业设计|基于springboot + vue外卖点餐系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
All for pursuit.42 分钟前
【二叉树-10】114.二叉树展开为链表
数据结构·c++·算法·leetcode·链表
叠层归一研究院44 分钟前
区分预算与通道诱导:Ω–L叠层体系的观测赋值与定量验证
人工智能·算法
BYSJMG1 小时前
计算机毕业设计选题推荐:基于大数据的快递物流运营数据分析与可视化,Spark与K-Means
大数据·算法·数据分析·spark·课程设计
怕浪猫1 小时前
分享一个做视频的skill,这条白板视频,每一笔都是代码画的
前端·javascript·面试
aa小小2 小时前
大屏自适应缩放方案
前端·数据可视化
阳明山水2 小时前
因果一致性正则化实战解析
人工智能·深度学习·算法·机器学习·架构