泛化物品

1 从「物品是什么」问起

普通背包里,一件物品就是一对数 (w,v)(w,v):给它 ww 的空间,得到 vv 的价值,给别的空间什么都不给。

但如果把「物品」理解成一个函数呢?

定义泛化物品

在容量为 CC 的背包问题里,泛化物品是一个定义在 0∼C0\sim C 上整数的函数 hh。给它分配费用 vv,能得到价值 h(v)h(v)。

用数组的说法:一个泛化物品就是一个数组 h[0…C]h[0\dots C]。

2 普通物品是特殊的泛化物品

  • 01 物品 (w,v)(w,v):只有 h(w)=vh(w)=v,其余全是 00。
  • 完全物品 (w,v)(w,v):当 vv 能被 ww 整除时 h(v)=v′⋅vwh(v)=v'\cdot\frac{v}{w}(即装几件拿几件的价值),其余为 00。
  • 多重物品 (w,v,m)(w,v,m):同上,但限制件数不超过 mm。
  • 一个物品组:h(v)h(v) 取组内所有费用恰为 vv 的物品的最大价值。

所以「泛化物品」不是新东西,只是把所有已有的背包对象统一成同一个形状。

3 泛化物品的和

真正有用的是运算。取两个泛化物品 hh 和 ll,要用一定的费用从两者中取得最大价值,该怎么算?

对固定的费用 vv,枚举分配给 hh 多少、给 ll 多少:

f(v)=max⁡0≤k≤v{h(k)+l(v−k)} f(v)=\max_{0\le k\le v}\bigl\{h(k)+l(v-k)\bigr\}

ff 自己也是一个定义在 0∼C0\sim C 上的函数,也就是一个新的泛化物品,称为 hh 与 ll 的和。

这一步的复杂度是 O(C2)O(C^2)。

定理替换定理

若把背包问题中的两个泛化物品替换成它们的和,不影响问题的答案。

理由是显然的:分配给这两件的总费用是固定的,怎么分配不影响可行性,所以只需取最优分配。

由此得到一个漂亮的结论:

求解一个背包问题,就是求它所有物品(泛化物品)之和;答案是这个和的 0∼C0\sim C 上的最大值。

4 用它重新看前面几讲

这个视角能把已有算法解释得很统一:

算法 在「求和」的框架下的含义
01 背包一维写法 把每个 01 物品逐个「加」进当前的和
分组背包 一个组先自己求和成一件泛化物品,再加进总和
有依赖的背包 子树先求和成一件泛化物品,父亲再与之求和

注意合并的复杂度:用朴素方式求和是 O(C2)O(C^2)。前面几讲之所以能做到 O(C)O(C),是因为利用了物品的特殊结构——01 物品的 hh 只有 h(w)=vh(w)=v 一个非零值,所以 max⁡\max 里只有两项需要比较。这就是为什么 01 背包的转移是 O(1)O(1) 而不是 O(C)O(C)。

说明泛化物品的意义

它不会给你一个更快的算法。它的价值在于统一视角:当你遇到一个从没见过的背包变形时,可以问自己两个问题:

  1. 这个问题的「物品」,作为泛化物品,h(v)h(v) 长什么样?
  2. 两件这样的物品,怎么求和?

想清楚这两问,算法往往就出来了。有依赖的背包正是这样被想出来的——子树是一件事先未知的泛化物品,只能先把它算出来再合并。

5 一个具体的例子

考虑「每个物品可以取 0,1,20,1,2 件,但第二件打折」这种奇怪规则。它显然不是 01/完全/多重中的任何一种。

用泛化物品描述:一件物品的 hh 是

h(0)=0,h(w)=v,h(2w)=v+v2,其余为 0 h(0)=0,\quad h(w)=v,\quad h(2w)=v+\tfrac{v}{2},\quad \text{其余为 } 0

它仍然是一个合法的泛化物品,所以仍然可以和别的物品「求和」。求和之后取最大值,就是答案。

只不过此时 hh 有 3 个非零位置,转移时要比 3 次而不是 2 次——这就是「物品越复杂,转移越慢」的由来。

6 小结

泛化物品是《背包问题九讲》里最抽象的一讲,但结论很朴素:

  • 每件物品都是一个函数 h(v)h(v);
  • 「把两件物品放在一起」就是一次 O(C2)O(C^2) 的卷积式求和;
  • 背包问题的答案,就是所有物品之和在 0∼C0\sim C 上的最大值。

它的用途不在加速,而在建立一个统一的思考框架。遇到新变形时,先问「它的 hh 是什么、怎么求和」,比直接猜状态转移方程更可靠。

7 相关题解

暂无相关题解