0-1背包和完全背包

26 年 3 月 9 日 星期一
627 字
4 分钟

0-1背包

Screenshot 2026-03-09 at 1.42.06 pm
Screenshot 2026-03-09 at 1.41.41 pm

以0-1背包为例分享一下 对于 “恰好”、“至多”、“至少”三种变形的理解和总结: 假设 数组为 nums,长度为n,总和为 target 对于正常的0-1背包问题(恰好-方案数)

py
# 记忆化搜索
def dfs(i,c):
  if i < 0:
    return 1 if c ==0 else 0
  if c < nums【i】:
    return dfs(i-1,c)
  return dfs(i-1,c)+dfs(i-1,c-nums【i】)
# 递推
f =1+0* target
for i in range(n):
  num = nums【i】
  for j in range(target,num-1,-1)
    f【j】 = f【j】 +f【j-num】

对于方案数问题:

  1. “恰好”问题边界为,仅 c==0 为1,其余为0 (1为合法,0为不合法情况)
  2. “至多”问题边界为,c>=0 为 1,其余为0
  3. “至少”问题边界为,c<=0为1,其余为0;

需要去除掉 上述代码中“c < nums【i】”的约束,使 c 可以达到 0 及以下 f 数组在递推时,需要将下界调整至 0, for j in range(target,-1,-1) or for j in range(target+1) 对于dfs(i,c),若 c<=0 则说明 前i个数字选或不选都可以,即无约束; 而在使用 f 数组进行存储时,f【0】 通过循环式子可以保持为2^(i-1),即记录了前i-1个数字选或不选的所有情况; 因此,可以得到 f【j】 = f【j】 + f【max(j-num,0)】

对于极值问题,和方案数问题的差别主要在边界设置以及当前问题的处理上,由 加 操作变为了 min/max 操作 对于正常的0-1背包问题(恰好-最大数)

py
def dfs(i,c):
  if i < 0:
    return 0 if c ==0 else -inf
  if c < nums【i】:
    return dfs(i-1,c)
  return max(dfs(i-1,c),dfs(i-1,c-nums【i】)+1)
# 递推
f =0+-inf】* target
for i in range(n):
  num = nums【i】
  for j in range(target,num-1,-1):
    f【j】 = max(f【j】,f【j-num】+1)

对于极值问题:

  1. “恰好”问题边界为,仅 c==0 为0,其余为 inf/-inf (对应求最小/求最大的不合法情况)
  2. “至多”问题边界为,c>=0 为 0,其余为 inf/-inf (对应求最小/求最大)
  3. “至少”问题边界为,c<=0为0,其余为 inf/-inf (对应求最小/求最大)

需要去除掉 上述代码中“c < nums【i】”的约束,使 c 可以达到 0 及以下 f 数组在递推时,需要将下界调整至 0, for j in range(target,-1,-1) or for j in range(target+1) 对于dfs(i,c),若 c<=0 则说明 前i个数字选或不选都可以; 而在使用 f 数组进行存储时,f【0】 通过循环式子记录了 前i-1个数字选或不选的极值情况; 因此,可以得到 f【j】 = f【j】 + f【max(j-num,0)】

完全背包

Screenshot 2026-03-09 at 1.43.04 pm

文章标题:0-1背包和完全背包

文章作者:Sirui Chen

文章链接:https://blog.siruichen.me/posts/0-1%E8%83%8C%E5%8C%85%E5%92%8C%E5%AE%8C%E5%85%A8%E8%83%8C%E5%8C%85[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。