最近两天为树形背包问题所困扰。 这一切的起因是一年前在 hackerrank 上做的一道题 A Knapsack Problem。
题目大意是:
给一棵 $N$ 个节点的树,节点 $i$ 代表一件价值为 $v[i]$,体积为 $s[i]$ 的物品。另有一个体积为 $M$ 的背包,要求在树上选一个连通块装进背包,使得所选物品的总价值最大。
数据范围:
$ N, M le 2000 $
朴素的做法复杂度是 $O(NM^2)$,TLE。一直没看editorial,拖到现在。做这题之前我已看过崔添翼的《背包九讲》,期间又读了2009年国家集训队徐持衡的论文《浅谈几类背包问题》,徐的论文中提到树形依赖背包问题有 $O(NM)$ 解法,我很高兴,然而看了以后并不能懂。最近又想起这道题,再去翻徐的论文,折腾了两天,才发现:
- 徐的论文讲的比较简略,确实有点难懂
- 徐所讨论的树形依赖背包问题和 A Knapsack Problem 根本不是同一个问题
徐论文中所谓的树形依赖背包问题指的是:
给一棵 $N$ 个节点的有根树,树的每个节点代表一件价值为 $v[i]$,体积为 $s[i]$ 的物品。另有一个体积为 $M$ 的背包,要求在树上选一个包含根节点的连通块装进背包,使得所选物品的总价值最大。
然而明确了这一点以后,我一时还是搞不懂徐持衡对此问题给出的$O(NM)$的树形DP解法。又花了些功夫才基本弄懂:
$dp[i][j]$ 表示选择了节点 $i$ (及其所有祖先节点) (即根节点到 $i$ 的路径——记作 $P_i$ ——上的所有节点),此外再在 $P_i$ 的左侧和子树 $i$ 中选择总体积不超过 $j$ 的物品的最大价值。