背包DP

dp · 浏览次数 : 0

小编点评

**01背包的意图** 01背包是每个物品只能选取两种方式的背包。其中,\\(01\\) 表示能够选取该物品的两种方式。 **暴力背包的实现** 暴力背包使用一个二维数组 \\(dp\\) 来存储在每个物品可以选择的最大价值。其中,\\(dp_{i,j}\\) 表示在前 \\(i\\) 个物品中,花费为 \\(j\\) 时所能获得的最大价值。 **优化后的转移方程** 优化后的转移方程为 \\(dp_j=\\max(dp_j,dp_{j-cost_i}+value_i)\\) ,其中 \\(cost_i\\) 是选择该物品的成本, \\(value_i\\) 是物品的价值。 **完全背包的意义** 完全背包指的是每一个物品可以被选取任意次。这与 \\(01\\)背包不同,因为每个物品只能选取两种方式。

正文

01 背包

\(01\) 的意图很明显,就是每个物品有 \(01\),即 不选 两种方式。

暴力

考虑设定一个状态 \(dp[i][j]\) 表示在前 \(i\) 个当中,花费为 \(j\) 所能获得的最大值。

转移可以:

\(dp_{i,j}=\max(dp_{i-1,j},dp_{i-1,j-cost_i}+value_i)\)

优化

不难发现当前的 \(dp_{i,j}\) 只和 \(i-1\) 的部分有关系,于是滚动数组即可优化掉一维。

优化后的转移方程如下:

\(dp_j=\max(dp_j,dp_{j-cost_i}+value_i)\)

由于修改 \(dp_j\) 的时候需要 \(dp_{j-cost_i}\) 的值,所以需要先修改 \(dp_j\)\(j\) 较大的值。

时间复杂度 \(O(nT)\) 其中 \(T\) 是物品总数。

空间复杂度 \(O(m)\)\(m\) 是背包最大容量。


完全背包

完全 的意义在哪里呢?在于每一个物品可以被选取任意次,而并非 \(01\) 背包的 \(0/1\)

暴力

仍然是 \(dp_{i,j}\) 表示在前 \(i\) 个当中花费为 \(j\) 时所能得到的最大花费。

首先,考虑一个显然的做法,枚举每一个物品的出现次数:

\(dp_{i,j}=\displaystyle \max_{k=0}^{\infty}(dp_{i-1,j-k\times cost_i}+k\times value_i,dp_{i,j})\)

优化

考虑如何去掉枚举 \(\max\) 的一维。

不难发现,只需要考虑 \(dp_{i,j}\)\(dp_{i-1,j-cost_i}+value_i\) 两部分即可。可为什么呢?

尝试使用数学归纳法来证明。

如果 \(dp_{i,j-cost_i}\) 是最优的,那么很显然它是要比从 \(dp_{i,j-cost_i\times k}\)\(k>1\))转移来至少是不亏的,因为 \(dp_{i,j-cost_i}\) 是可以从 \(dp_{i,j-cost_i\times k}\) 转移来的。于是 \(dp_{i,j}\) 也是最优的。又由于对于 \(\forall i\)\(dp_{i,0}=0\) 也是最优的,得证。

换言之,由于 \(dp_{i,j-cost_i}\) 的局部最优性保证了 \(dp_{i,j}\) 的最优性。

所以,此时转移需要 先转移 \(dp_{i,j-cost_i}\) 再转移 \(dp_{i,j}\)

根据 \(01\) 背包的经验,可以很轻松的压掉一维。


多重背包

如何理解 多重 的意义呢?

意义比较容易理解,就是每一个物品只有有限个 \(num_i\)

暴力

首先,还是有一个很暴力的解法:

考虑将所有的物品看成 \(num_i\) 个物品,然后直接 \(01\) 背包。

时间复杂度是 \(O(m\displaystyle \sum_{i=1}^n num_i)\)

二进制优化

熟知,我们可以使用 \(k\) 位二进制来表示 \(1\)\(2^k\) 的所有数。

首先设 \(2^{\alpha_i+1}\le num_i < 2^{\alpha_i+2}\)

\(num_i\) 拆分成 \(\displaystyle\sum_{j=1}^{\alpha_i}2^i+(num_i-2^{\alpha_i+1}+1)\),这样就可以表示出 \(1\)\(num_i\) 之间的所有数。

\(Eg:10=1+2+4+3\)

之后再次用 \(01\) 背包就可以了。

时间复杂度为 \(O(m\displaystyle \sum_{i=1}^n \log_2num_i)\)


混合背包

何为混合?

就是将前面三种背包加起来。

非常简单。


二维费用背包

如果限制有两位呢,怎么求解?

设置状态 \(dp_{i,j,k}\) 表示在前 \(i\) 个物品中,限制 \(1\) 的花费为 \(j\),限制 \(2\) 的花费为 \(k\) 时所能得到的最大价值。

由于此时是三维的,所以需要使用 \(01\) 背包的方法再次优化掉第一维。

然后,枚举 \(i,j,k\) 即可。

时间复杂度 \(O(nT_{限制1}T_{限制2})\)


分组背包

考虑先枚举组数,然后再每一组中做 \(01\) 背包。

时间复杂度 \(O(nm)\) 其中 \(n\)\(k\) 组的物品的总种类。


有依赖的背包

有两种方法:

  1. 分类讨论

  2. 先计算子节点,再计算父节点。

与背包DP相似的内容:

背包DP

01 背包 \(01\) 的意图很明显,就是每个物品有 \(01\),即 选 和 不选 两种方式。 暴力 考虑设定一个状态 \(dp[i][j]\) 表示在前 \(i\) 个当中,花费为 \(j\) 所能获得的最大值。 转移可以: \(dp_{i,j}=\max(dp_{i-1,j},dp_{i-1

背包DP——多重背包

多重背包也是 0-1 背包的一个变式。与 0-1 背包的区别在于每种物品有 k 个,而非一个。 朴素 直接把相同的每个物品视作各个单独的物品,没有关联,仅条件相同; 转换后直接用01背包的状态转移方程 注意:在大数据下容易爆空间时间 二进制分组优化 与朴素相比,优化利用二进制原理(任意数可以由多个不

LeetCode 周赛上分之旅 #45 精妙的 O(lgn) 扫描算法与树上 DP 问题

⭐️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度也更复杂。在这个专栏里,小彭与你分享每场 LeetCode

01背包问题

题目 题目描述 有 N N N 件物品和一个容量是 V V V 的背包。每件物品只能使用一次。 第 i i i 件物品的体积是 v i v_i vi​,价值是 w i w_i wi​。 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。 输入格式 第一行两个整

01背包问题的js解决方式

如果你有兴趣看这个相信你已经对背包问题有所了解,所以关于背包问题的描述,我就不写了。只记录一下自己对这个问题的一些看法和思考,于我而言,这个东西现在困扰我的是如何确定最优解。实质上关于背包问题网上的东西我大体都有看过,对于这个问题,常见的就是使背包重量动态增长,然后遍历每个要装入的这些包裹,当包裹的

LeetCode 周赛 350(2023/06/18)01 背包变型题

> **本文已收录到 [AndroidFamily](https://github.com/pengxurui/AndroidFamily),技术和职场问题,请关注公众号 [彭旭锐] 和 [BaguTree Pro] 知识星球提问。** - 往期回顾:[LeetCode 单周赛第 348 场 · 数

经典背包系列问题

经典背包系列问题 作者:Grey 原文地址: 博客园:经典背包系列问题 CSDN:经典背包系列问题 问题一 题目描述 在 n 个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为Ai (每个物品只能选择一次且物品大小均为正整数) 题目链接:LintCode 92 · Ba

贪心算法--背包问题--分数背包

博客地址:https://www.cnblogs.com/zylyehuo/ # -*- coding: utf-8 -*- stuffs = [(60, 10), (100, 20), (120, 30)] # 每个商品元组表示(价格, 重量) stuffs.sort(key=lambda x:

毕业季,终于毕业了!

2023.10-2024.06十年有余,没想到在一家公司可以干这么久,属于超长期服役。原本3年前掀完桌子就该背包走人的,没想到又赖了三年。公司属于危机自救无奈减兵过冬,在国法的基础上还加了一点点毕业礼包,在这里真心感谢老板、感谢CCTV、MTV、BTV、皇恩浩荡。 从6.18接到人事通知到6.21最

彻底理解Linux的DISPLAY变量的作用

背景 最近遇到个两年前遇到的问题,使用virt-manager提示(virt-manager:873): Gtk-WARNING **: 14:53:28.147: cannot open display: :1,当时专门运维的同事帮忙临时调了下DISPLAY变量,好像是将:1改成了SSH用户本地I