【题目】BZOJ-4987 Tree

探讨了在给定树状结构中寻找k个点,使相邻点间距离之和最小的问题。通过分析路径特性,引入状态转移方程,实现树形背包算法优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

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

1⩽N⩽30001\leqslant N\leqslant 30001N3000


思路

题目要求的是从点A1A_1A1开始,依次经过A2,A3,…A_2,A_3,\dotsA2,A3,,最后到达AkA_kAk走过的最短路程。

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

其次,A1A_1A1AkA_kAk这条路径上的边被经过一次,其余的边都被经过两次。可以通过画图验证。

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

在状态后面添加一维jjj,表示选择的iii个点中有jjj个点是A1A_1A1AkA_kAk这条路径的端点(起点A1A_1A1或终点AkA_kAk)。jjj的范围是[0,2][0,2][0,2]。下面分情况讨论。

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

很好看的状态转移方程:

f[u][i+j][0]=min⁡{f[u][i][0]+f[v][j][0]+len(u,v)⋅2}f[u][i+j][1]=min⁡{f[u][i][0]+f[v][j][1]+len(u,v)f[u][i][1]+f[v][j][0]+len(u,v)⋅2f[u][i+j][2]=min⁡{f[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\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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值