01 背包

发表于 2025-07-08 383 字 2 min read

文章目录
01 背包的状态定义、滚动数组写法与逆序遍历的原因。

本篇对应源码见仓库 solutions/xcpc/algorithm/dp/knapsack-01/。

问题分析

  • 给定背包最大容量 V, n 件物品,每件物品有重量(体积)w, 价值 v,每件物品最多选一次,求背包能装下物品的最大总价值。
  • 对每件物品考虑选或者不选,选还需要考虑背包能不能装下。

状态定义

  • 使用滚动数组(一维)
  • dp[j]dp[j] 背包容量为 jj 时能装的最大价值

遍历方式

  • 二重循环
  • 第一层枚举物品(for i in 1..nfor\ i\ in\ 1..n)
  • 第二层逆序枚举背包容量(for j in W..w[i]for \ j \ in\ W..w[i])

状态转移方程

dp[j] = max(dp[j], dp[j - w[i] + v[j]

拓展问题

请注意对不同问题的 dpdp 数组的定义,初始化,状态转移方程的异同。

求可行性(恰好装满)

  • 状态定义: dp[j]dp[j] 为容量为 jj 的背包能否装满
  • 初始化: dp[0] = true, dp[1..n] = false
  • 状态转移: dp[j] = dp[j] | dp[j - w[i]]

求方案数(恰好装满)

  • 状态定义: dp[j]dp[j] 为容量为 jj 的背包能够装满的方案总数
  • 初始化: dp[0] = 1, dp[1..n] = 0
  • 状态转移: dp[j] = dp[j] + dp[j - w[i]]

求最大价值

  • 状态定义:dp[j]dp[j] 为容量为 jj 的背包能装下的最大价值
  • 初始化: dp[0..n] = 0(不要求恰好装满), dp[0] = 0, dp[1..n] = -inf(要求恰好装满)
  • 状态转移: dp[j] = max(dp[j], dp[j - w[i]] + v[i](不要求恰好装满), if(dp[j - w[i]] != -inf) dp[j] = max(dp[j], dp[j - w[i]] + v[i]