$\texttt{Description}$
给你 $n$ 个节点的树,要你选择 $k$ 个点 $a_1,a_2…a_k$,使得 $\sum\limits_{i=1}^{i<k} dis(a_i,a_{i+1})$ 最小,$dis(u,v)$ 表示节点 $u$ 和 $v$ 的距离。树的边权均为正整数且小于 $10^5$。
$\texttt{Data Range:}1\le k\le n\le 3000$
$\texttt{Solution}$
算是比较毒瘤的一个树形 dp了吧。需要充分挖掘题目性质,否则直接树形背包会非常痛苦并且最后发现做不出来。
首先,我们选出的 $k$ 个点一定是紧密相连的,否则如果中间有空隙,那么用这些空隙位置的点替换原来的点一定更优。
因此选择的 $k$ 个点一定构成一棵树。当选择好了这棵树后,我们需要找到一条最短的遍历整棵树的路径。那么这条最短路径的长度一定是所有边权之和的两倍减去树的直径。因为路径经过了一条边还要回来,但是有些路径是可以不回来的。选择的这些只经过一次的边构成一条链,我们自然希望这条链最长,因此这条链长度即为树的直径。
如果直接进行树形背包,不知道直径是哪条链,也就没法 dp。因此考虑在状态中加入对直径的限制:$dp_{u,i,x}$ 表示在以 $u$ 为根的子树中,选择 $i$ 个点,其中包含了 $x$ 个直径端点($0\le x\le 2$),最小代价是多少。
有一个注意的地方,树形背包的填表法时间复杂度是假的,之前没被卡过但在这题上被卡了。只有刷表法复杂度是经过严格证明 $O(n^2)$ 的。
$v$ 是 $u$ 的儿子,$len(u,v)$ 表示连接 $u,v$ 两点的边的长度。
$\texttt{Code}$
1 |
|