给出
n
≤
100
n\leq100
n≤100个点的树,树上有边权。给出
k
≤
100
k\leq100
k≤100,求问保留
k
k
k条边权的最大值是多少。保留
k
k
k条边权指的是你要保留子树就必须要保留与此连接的边,也就是不能断开。
f
u
,
j
f_{u,j}
fu,j表示
u
u
u这个子树保留
j
j
j条边的最大值。答案即为
f
1
,
k
f_{1,k}
f1,k。转移的时候可以认为是对
u
u
u这个子树做一个容量
j
j
j的背包,对每个子树做01背包,因此对
j
j
j要逆序枚举。同时容量显然也不会超过子树大小
−
1
-1
−1。
转移方程
f
u
,
j
=
m
a
x
{
f
u
,
j
−
k
−
1
+
f
v
,
k
+
e
w
}
f_{u,j}=max\{f_{u,j-k-1}+f_{v,k}+e_{w} \}
fu,j=max{fu,j−k−1+fv,k+ew}。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=105;
struct edge{ int v,w; };
vector<edge> go[N];
int f[N][N];
int sz[N];
int n,tot;
void dfs(int u,int fa) {
f[u][0]=0;
sz[u]=1;
for(auto &e:go[u]) {
int v=e.v,w=e.w;
if(v==fa) continue;
dfs(v,u);
sz[u]+=sz[v];
for(int j=min(sz[u]-1,tot);j>=1;j--) {
int up=min(j,sz[v]);
for(int k=0;k<up;k++) {
f[u][j]=max(f[u][j],f[u][j-k-1]+f[v][k]+w);
}
}
}
}
int main() {
scanf("%d%d",&n,&tot);
for(int i=1;i<n;i++) {
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
go[u].push_back({v,w});
go[v].push_back({u,w});
}
dfs(1,0);
printf("%d\n",f[1][tot]);
return 0;
}