解法
首先考虑当n==k时,答案就是
所
有
边
权
∗
2
−
直
径
的
长
度
所有边权*2-直径的长度
所有边权∗2−直径的长度。然后k<n时,就是求一个大小为k的联通块,使得联通块内的
所
有
边
权
∗
2
−
直
径
的
长
度
所有边权*2-直径的长度
所有边权∗2−直径的长度最小。考虑树型背包。
设f[i][j][0]表示以i为根的子树,选了j个点(i自己也在这个联通块里),总边权*2的最小值.f[i][j][1]表示以i为根的子树,从i开始一口气选了j个点组成的一条链的答案最小是多少。f[i][j][2]表示以i为根的子树,选了一个大小为j的联通块(包含i),答案是多少。
转移时稍微画一下图就可以写出式子了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e3+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,k;
struct edge{
int v,p,w;
}e[maxn<<1];
int h[maxn],cnt;
inline void add(int a,int b,int c){
e[++cnt].p=h[a];
e[cnt].v=b;
e[cnt].w=c;
h[a]=cnt;
e[++cnt].p=h[b];
e[cnt].v=a;
e[cnt].w=c;
h[b]=cnt;
}
int val[maxn],f[maxn][maxn][3];
void dfs(int u,int fa){
for(int i=h[u];i;i=e[i].p){
int v=e[i].v;
if(v==fa)continue;
val[v]=e[i].w;
dfs(v,u);
}
}
int sz[maxn];
const int inf=0x3f3f3f3f;
void dp(int u,int fa){
sz[u]=1;
for(int i=h[u];i;i=e[i].p){
int v=e[i].v;
if(v==fa)continue;
dp(v,u);
for(int i=sz[u]+1;i<=sz[u]+sz[v];i++)f[u][i][0]=f[u][i][1]=f[u][i][2]=inf;
for(int i=sz[u];i>=1;i--){
for(int j=1;j<=sz[v];j++){
f[u][i+j][0]=min(f[u][i+j][0],f[u][i][0]+f[v][j][0]+val[v]*2);
f[u][i+j][1]=min(f[u][i+j][1],f[u][i][1]+f[v][j][0]+val[v]*2);
f[u][i+j][1]=min(f[u][i+j][1],f[u][i][0]+f[v][j][1]+val[v]);
f[u][i+j][2]=min(f[u][i+j][2],f[u][i][2]+f[v][j][0]+val[v]*2);
f[u][i+j][2]=min(f[u][i+j][2],f[u][i][1]+f[v][j][1]+val[v]);
f[u][i+j][2]=min(f[u][i+j][2],f[u][i][0]+f[v][j][2]+val[v]*2);
}
}
sz[u]+=sz[v];
}
}
int main(){
n=read(),k=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
add(u,v,w);
}
dfs(1,0);
dp(1,0);
int ans=inf;
for(int i=1;i<=n;i++){
if(sz[i]>=k)ans=min(ans,f[i][k][2]);
}
printf("%d\n",ans);
return 0;
}