01背包

last modify

问题简述

给定最多能容纳 V 体积的背包,和 n 个物品,每个物品有重量(w)和体积(v)两个属性;
求背包能放的最大重量;
每个物品的重量(w)和体积(v)保存在数组 vw 中;

示例1:
    输入:10,2,[[1,3],[10,4]]
    返回:4
示例2:
    输入:10,2,[[1,3],[9,8]]
    返回:11

01背包_牛客题霸_牛客网

总结

  • 熟练掌握思路 1 的优化路径(解新题);

  • 牢记 01 背包的一维转移方程

    • 优化目标是最大重量:dp[i] = max(dp[i], dp[i - v[i]] + w[i])

    • 优化目标是最小空间:dp[i] = min(dp[i], dp[i - w[i]] + v[i])

思路1:暴力递归+记忆化搜索 -> 动态规划

Python:写法1)暴力递归+记忆化搜索
Python:写法2)使用标准库提供的缓存(爆栈)
  • 不知道什么原因无法通过最长的用例,好像 lru_cachesetrecursionlimit 不能同时生效;

Python:写法3)将暴力递归转成动态规划

思路2:一维 dp(内存优化)

  • 因为每次更新第 i 行数据时,只与 i-1 行有关,所以可以使用一维数组优化;

Python

为什么一维 dp 中要逆序遍历体积?

二维状态的转移方程:dp[i][j]=max(dp[i-1][j], dp[i-1][j-v[i]] + w[i]); 一维状态的转移方程:dp[j]=max(dp[j], dp[j-v[i]] + w[i]);

可以看到二维中更新第 i 层数据用的都是 i - 1 层的数据,因为第 i - 1 层的数据已经固定,所以正序逆序遍历都无所谓;而如果在一维状态中正序遍历,那么 dp[j-v[i]] 会在 dp[j] 前被更新,导致 dp[j] 得到错误的答案;

关于01背包和完全背包的优化的体积顺序问题_听-起风了的博客-CSDN博客

思路3:另一种尝试

  • 思路 1 是最直观的尝试方法;但存在一个问题,就是当 V 非常大时,可能会超时;

  • 此时可以尝试另一个递推思路,定义 dp[i][w] 表示前 i 个物品达到重量为 w 时需要的最小空间;

  • 最后的答案为满足 dp[n][w] <= V 时最大的 w;

  • 事实上,对比后可以发现两者的转移方程非常相似:

    • 最大重量:dp[i] = max(dp[i], dp[i - v[i]] + w[i])

    • 最小空间:dp[i] = min(dp[i], dp[i - w[i]] + v[i])

Python:写法1)二维 dp
Python:写法2)一维 dp

代码验证

  • 因为上面一些代码不能通过 OJ,所以离线写了一个对数器验证正确性(假设能通过 OJ 的 Solution1 是正确的);

Python

Last updated