【题目】BZOJ-4987 Tree

题目大意

从前有棵树。找出 k k k个点 A 1 , A 2 , … , A k A_1,A_2,\dots,A_k A1,A2,,Ak,使得 ∑ i = 1 k − 1 d i s t ( A i , A i + 1 ) \sum\limits_{i=1}^{k-1}dist(A_i,A_{i+1}) i=1k1dist(Ai,Ai+1)最小。

1 ⩽ N ⩽ 3000 1\leqslant N\leqslant 3000 1N3000


思路

题目要求的是从点 A 1 A_1 A1开始,依次经过 A 2 , A 3 , … A_2,A_3,\dots A2,A3,,最后到达 A k A_k Ak走过的最短路程。

首先,这 k k k个点中任意两点之间一定不会有这 k k k个点以外的点,否则把这个点纳入 k k k个点内,得到的方案更优。于是这 k k k个点构成了一棵大小为 k k k的树,并且是原树的一部分。

其次, A 1 A_1 A1 A k A_k Ak这条路径上的边被经过一次,其余的边都被经过两次。可以通过画图验证。

根据树形背包的套路,容易定出状态 f [ u ] [ i ] f[u][i] f[u][i],表示从以 u u u为根的子树中选出包含 u u u i i i个点对答案的贡献,然后把点 u u u自身以外的 i − 1 i-1 i1个点分配给每个儿子 v v v。但是边 ( u , v ) (u,v) (u,v)被经过的次数无法确定。

在状态后面添加一维 j j j,表示选择的 i i i个点中有 j j j个点是 A 1 A_1 A1 A k A_k Ak这条路径的端点(起点 A 1 A_1 A1或终点 A k A_k Ak)。 j j j的范围是 [ 0 , 2 ] [0,2] [0,2]。下面分情况讨论。

  • u u u已讨论的部分子树和 v v v的子树中都没有路径的端点,那么这条路径一定没有经过边 ( u , v ) (u,v) (u,v)。这条边被经过了两次。
  • u u u已讨论的部分子树中没有路径的端点,而 v v v的子树中有一个,那么这条路径从 v v v的子树内出发,经过边 ( u , v ) (u,v) (u,v),走到了已讨论的子树外的部分。这条边被经过了一次。
  • u u u已讨论的部分子树中有一个路径的端点,而 v v v的子树中没有,那么这条路径从 u u u已讨论的子树内出发,没有进入 v v v的子树内,说明路径没有经过边 ( u , v ) (u,v) (u,v)。这条边被经过了两次。
  • u u u已讨论的部分子树中没有路径的端点,而 v v v的子树中有两个,那么这条路径被包含在 v v v的子树内,没有经过边 ( u , v ) (u,v) (u,v)。这条边被经过了两次。
  • u u u已讨论的部分子树和 v v v的子树各有一个端点,那么这条路径一定经过边 ( u , v ) (u,v) (u,v)。这条边被经过了一次。
  • u u u已讨论的部分子树中有两个路径的端点,而 v v v的子树中没有,那么这条路径被包含在 u u u已讨论的子树内,没有经过边 ( u , v ) (u,v) (u,v)。这条边被经过了两次。

很好看的状态转移方程:

f [ u ] [ i + j ] [ 0 ] = min ⁡ { f [ u ] [ i ] [ 0 ] + f [ v ] [ j ] [ 0 ] + l e n ( u , v ) ⋅ 2 } f [ u ] [ i + j ] [ 1 ] = min ⁡ { f [ u ] [ i ] [ 0 ] + f [ v ] [ j ] [ 1 ] + l e n ( u , v ) f [ u ] [ i ] [ 1 ] + f [ v ] [ j ] [ 0 ] + l e n ( u , v ) ⋅ 2 f [ u ] [ i + j ] [ 2 ] = min ⁡ { f [ u ] [ i ] [ 0 ] + f [ v ] [ j ] [ 2 ] + l e n ( u , v ) ⋅ 2 f [ u ] [ i ] [ 1 ] + f [ v ] [ j ] [ 1 ] + l e n ( u , v ) f [ u ] [ i ] [ 2 ] + f [ v ] [ j ] [ 0 ] + l e n ( u , v ) ⋅ 2 \begin{aligned} f[u][i+j][0]&=\min\{f[u][i][0]+f[v][j][0]+len(u,v)\cdot 2\}\\ f[u][i+j][1]&=\min\begin{cases} f[u][i][0]+f[v][j][1]+len(u,v)\\ f[u][i][1]+f[v][j][0]+len(u,v)\cdot 2 \end{cases}\\ f[u][i+j][2]&=\min\begin{cases} f[u][i][0]+f[v][j][2]+len(u,v)\cdot 2\\ f[u][i][1]+f[v][j][1]+len(u,v)\\ f[u][i][2]+f[v][j][0]+len(u,v)\cdot 2 \end{cases} \end{aligned} f[u][i+j][0]f[u][i+j][1]f[u][i+j][2]=min{f[u][i][0]+f[v][j][0]+len(u,v)2}=min{f[u][i][0]+f[v][j][1]+len(u,v)f[u][i][1]+f[v][j][0]+len(u,v)2=minf[u][i][0]+f[v][j][2]+len(u,v)2f[u][i][1]+f[v][j][1]+len(u,v)f[u][i][2]+f[v][j][0]+len(u,v)2

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值