T1 set
选取的 k 个点在树上形成一个连通子树,然后我们考虑树形 DP。我们知道所选的路径一定是从树的直径上往下走,然后遇到分叉就走过去,然后再回到直径上。所以直径上的边权只算一次,其他的边权算两次。
设 f i , j , k f_{i, j, k} fi,j,k 表示起点和终点有 k 个在以 i 为根的子树中,且选了 j 个点时的最小代价。那么我们有:
f x , j + k , 2 = min k = 0 , j = 0 k ≤ s i z e [ y ] , j ≤ s i z e [ x ] { f x , j , 2 + f y , k . , 0 + 2 w i , f x , j , 1 + f y , k , 1 + w i , f x , j , 0 + f y , k , 2 + 2 w i } f x , j + k , 1 = min k = 0 , j = 0 k ≤ s i z e [ y ] , j ≤ s i z e [ x ] { f x , j , 0 + f y , k , 1 + w i , f x , j , 1 + f y , k , 0 + 2 w i } f x , j + k , 0 = min k = 0 , j = 0 k ≤ s i z e [ y ] , j ≤ s i z e [ x ] { f x , j , 0 + f y , k , 0 + 2 w i } \begin{aligned} & f_{x, j+k, 2} = \min_{k=0, j = 0}^{k \leq size[y], j \leq size[x]}\lbrace f_{x, j, 2} + f_{y, k., 0} + 2w_i , \; f_{x, j, 1} + f_{y, k, 1} + w_i, \; f_{x, j, 0} + f_{y, k, 2} + 2w_i \rbrace \\ \\ & f_{x, j +k, 1} = \min_{k=0, j=0}^{k \leq size[y],j \leq size[x]} \lbrace f_{x, j, 0} + f_{y, k, 1} + w_i, \; f_{x, j, 1} + f_{y, k, 0} + 2w_i \rbrace \\ \\ & f_{x, j + k, 0} = \min_{k=0,j=0}^{k \leq size[y],j \leq size[x]} \lbrace f_{x, j, 0} + f_{y, k, 0} + 2w_i \rbrace \end{aligned} fx,j+k,2=k=0,j=0mink≤size[y],j≤size[x]{fx,j,2+fy,k.,0+2wi,fx,j,1+fy,k,1+wi,fx,j,0+fy,k,2+2wi}fx,j+k,1=k=0,j=0mink≤size[y],j≤size[x]{fx,j,0+fy,k,1+wi,fx,j,1+fy,k,0+2wi}fx,j+k,0=k=0,j=0mink≤size[y],j≤size[x]{fx,j,0+fy,k,0+2wi}
其中 size 表示这颗以 x 为根的子树的大小,时间复杂度均摊下来是 O ( n 2 ) O(n^2) O(n2).代码如下:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 5050
#define MAXM 10010
#define INFI 0x3f3f3f3f
int ans = 0;
int n = 0; int k = 0;
int tot = 0;
int first[MAXN] = { 0 };
int nxt[MAXM] = { 0 };
int to[MAXM] = { 0 };
int value[MAXM] = { 0 };
void add(int x, int y, int weight){
nxt[++tot] = first[x];
first[x] = tot;
to[tot] = y;
value[tot] = weight;
}
int size[MAXN] = { 0 };
int f[MAXN][MAXN][5] = { 0 };
void dfs(int x, int fa){
size[x] = 1;
f[x][1][0] = 0; f[x][1][1] = 0; f[x][1][2] = 0;
for(int e = first[x]; e; e = nxt[e]){
int y = to[e];
if(y == fa) continue;
dfs(y, x);
for(int j = size[x]; j; j--){
for(int k = size[y]; k; k--){
f[x][j+k][2] = min(f[x][j+k][2], f[x][j][0] + f[y][k][2] + 2 * value[e]);
f[x][j+k][2] = min(f[x][j+k][2], f[x][j][1] + f[y][k][1] + value[e]);
f[x][j+k][2] = min(f[x][j+k][2], f[x][j][2] + f[y][k][0] + 2 * value[e]);
f[x][j+k][1] = min(f[x][j+k][1], f[x][j][0] + f[y][k][1] + value[e]);
f[x][j+k][1] = min(f[x][j+k][1], f[x][j][1] + f[y][k][0] + 2 * value[e]);
f[x][j+k][0] = min(f[x][j+k][0], f[x][j][0] + f[y][k][0] + 2 * value[e]);
}
}
size[x] += size[y];
}
ans = min(ans, f[x][k][2]);
}
int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i < n; i++){
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
add(x, y, w); add(y, x, w);
}
ans = INFI;
memset(f, 0x3f, sizeof(f));
dfs(1, 0);
printf("%d\n", ans);
return 0;
}