背包DP

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. 先计算子节点,再计算父节点。