Tree
Description
从前有棵树。
找出 k 个点 A 1 , A 2 , · · · , A k 。
∑ k−1
使得 i=1 dis(A i A i+1 ) 最小。
Input
第一行两个正整数 n, k, 表示数的顶点数和需要选出的点个数。
接下来 n − 1 行每行 3 个非负整数 x, y, z, 表示从存在一条从 x 到 y 权值为 z 的边。
1 ≤ k ≤ n。
1 ≤ x, y ≤ n。
1 ≤ z ≤ 10 5 。
Output
一行一个整数, 表示最小的距离和。
Scoring
对于 10% 的数据, n ≤ 10。
对于另外 10% 的数据, k = n。
对于另外 20% 的数据, n ≤ 50。
对于另外 20% 的数据, n ≤ 200。
对于 100% 的数据, n ≤ 3000。
标解是直接dp,但也可以点分治。
首先注意到答案一定是一个树上联通块,那么点分治后只需要考虑包含根的联通块,那么转化成一个树形依赖dp。
另外需要注意到最终的答案在点分治下,可以存在两条从根出发的链只走一次,其他的需要走两次。
令$F[x][y][0/1]$表示以x为根,选y个点,是否存在从根出发只走一次的链,
那么对于每个点$F[x][1][0]=2*d,F[x][1][1]=d$,d表示从他父亲到他的边长。
有转移
$$
F[x][y+k][0]=min(F[son][k][0]+F[x][y][0])
$$
$$
F[x][y+k][1]=min(F[son][k][0]+F[x][y][1],F[son][k][1]+F[x][y][0]-d)
$$
最后在根节点做一次背包,$G[x][k]$表示选了$x$个点,其中有$k$条只走一次的链$k=0,1,2$,这个直接背包就行。
最后答案取$min(G[m][0],G[m][1],G[m][2])$
复杂度很玄学,不知道。但跑得飞快。
这道题最关键的地方是,dp跑for循环的时候,一定只枚举子树size的前缀和,并且不要写$F[x][y-k]$,$F[x][y+k]$要快的多。具体可以看代码的注释
代码:
1 |
|