题目传送门
树形dp,(f_{i,j})表示以i为根,子树删j条边的最少苹果数
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,q,head[101],si[101],m,pp,ans,ss[101],ll[101],oo[101];
int f[101][101];
struct kkk {
int to,next,v;
}e[500];
inline void add(int x,int y,int vv) {
e[++pp].to = y;
e[pp].v = vv;
e[pp].next = head[x];
head[x] = pp;
oo[y]++;
}
inline int dp(int rt,int fa,int le) {
f[rt][0] = 0;
if(e[head[rt]].to == fa && oo[rt] == 1) {
f[rt][1] = le;
si[rt] = 1;
return 1;
}
int sum = 0,len = 0,so[2],tot = -1;
for(int i = head[rt];i; i = e[i].next) {
int u = e[i].to;
if(u == fa) continue;
si[rt] += dp(u,rt,e[i].v);
so[++tot] = u;
}
si[rt]++;
for(int i = 1;i <= min(m,si[rt] - 1); i++)
for(int k = 0;k <= 1; k++)//二叉树,两个儿子
for(int j = 0;j <= si[so[k]]; j++)
//因为一共删i条,所以左子树删j条,那右子树就删i-j条
f[rt][i] = min(f[rt][i],f[so[k]][j] + f[so[k^1]][i-j]);
if(m >= si[rt]) f[rt][si[rt]] = ll[rt];
return si[rt];
}
inline int dfs(int rt,int fa,int le) {
for(int i = head[rt];i; i = e[i].next) {
int u = e[i].to;
if(u == fa) continue;
ll[rt] += dfs(u,rt,e[i].v);
}
return ll[rt] = ll[rt] + le;
}
int main() {
memset(f,0x3f3f3f,sizeof(f));
scanf("%d%d",&n,&q);
m = n - q - 1;
for(int i = 1;i < n; i++) {
int x,y,t;
scanf("%d%d%d",&x,&y,&t);
add(x,y,t);
add(y,x,t);
ans += t;
}
dfs(1,0,0);
dp(1,0,0);
printf("%d",ans - f[1][m]);
//总数减去最少去除量
return 0;
}