\(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\) 组的物品的总种类。
有两种方法:
分类讨论
先计算子节点,再计算父节点。