diff --git a/TangDou/AcWing/BeiBao/6.md b/TangDou/AcWing/BeiBao/6.md index 74aa3d8..68f3a0c 100644 --- a/TangDou/AcWing/BeiBao/6.md +++ b/TangDou/AcWing/BeiBao/6.md @@ -178,22 +178,27 @@ int main() { ``` ### 七、疑问解答  -#### $Q1$:为什么可以引入单调队列对多重背包进行优化? -$A$:因为朴素版本三层循环,太慢了,要想办法优化?怎么优化的呢?因为发现每个新值要想更新$f[i][j]$值,第$i$件物品,最多有$s_i$件,我们可以选择$0 \sim s_i$个,同时,由于$i$物品的体积是$v_i$,也就是我们在拿物品$i$时,有一个关系 -
+#### $Q_1$:原理解析 +多重背包:物品个数是复数个,但又不是无限个。 +- 当作$01$背包来理解,$s$个物品当成$s$次$01$背包操作。然后优化的话通过 **二进制** 来优化。 +- 当作完全背包来理解,就是有数量限制的完全背包,而这个数量限制就可以理解成 **滑动窗口的长度**,然后优化通过 **单调队列** 来优化。 -| | 拿$0$个 | 拿$1$个 | 拿$2$个 | ... | 拿$s$个 | -| ---- | ----------- | --------------- | ------------------- | --- | ------------------- | -| 体积 | $k$ | $k-v$ | $k-2*v$ | ... | $k-s*v$ | -| 价值 | $f[i-1][k]$ | $f[i-1][k-v]+w$ | $f[i-1][k-2*v]+2*w$ | ... | $f[i-1][k-s*v]+s*w$ | -
+队列的单调性就是基于 +$$f[i][j] = max(f[i - 1][j], f[i - 1][j - v] + w,.....,f[i - 1][j - k * v] + k * w$$ + +要将前$i - 1$个物品的方案基础上不停尝试放入第$i$个物品,遍历取最大值。 +$f[i - 1][j - k*v] + k *w$表示,总空间是$j$,有且仅有$k$个物品$i$,其余空间通过前$i - 1$个物品填充的最大价值。 + +多重背包因为有数量限制,向前遍历的个数$k$是受到数量$s$限制的。 + +所以要将$max$中的每个元素$f[i - 1][j], f[i - 1][j - v] + w,.....,f[i - 1][j - k * v] + k * w$,通过维护单调队列,来获得当前窗口宽度$s$范围内的最大值。 + +并且在$j = j + v$后,队列中所有元素对应状态与当前背包空间差增加了$v$,可以多放一个物品$i$,每个元素对应的价值增加$w$,全部都加一个$w$,所以单调性不发生任何变化。 -**总结**: -* 往前最多看$s$个 -* $f[i][j]$ 跳跃性依赖 于$f[i-1][j - x * v]$,想要求什么呢?求离我距离最多$s$个数的最大值。这数不用每次现去查找,可用单调队列动态维护来优化查询。 +两种优化可以理解成两种思路的进化路线。 -#### $Q2$:单调队列中装的是什么? +#### $Q_2$:单调队列中装的是什么? $A$:是体积,是$f[i][j]$可以从哪些 **体积** 转移而来。比如当前$i$物品的体积是$v_i=2$,个数是$3$,那么$f[i][j]$可以从 $$ \large \left\{\begin{array}{l} @@ -205,7 +210,7 @@ $$ $$ 转移而来,当然,还需要判断一下是不是你的背包能装下那么多,一旦装不下了就别硬装了。 -#### $Q3$:只记录体积怎么计算最大价值? +#### $Q_3$:只记录体积怎么计算最大价值? $A$:只记录了所关联的体积,最大价值是现用现算的,办法是 $$\large f[i][k] = f[i - 1][q[hh]] + (k - q[hh]) / v * w$$