|
|
#include <bits/stdc++.h>
|
|
|
|
|
|
using namespace std;
|
|
|
const int N = 110;
|
|
|
const int M = N << 1;
|
|
|
int n; // 表示树的节点数
|
|
|
int m; // 表示要保留的树枝数量(背包容量)
|
|
|
int h[N], e[M], w[M], ne[M], idx;
|
|
|
int st[N]; // 是不是访问过
|
|
|
int f[N][N]; // f[u][j]:表示所有以u,为树根的子树中选,选j条边的最大价值
|
|
|
// 邻接表模板
|
|
|
void add(int a, int b, int c) {
|
|
|
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
|
|
|
}
|
|
|
|
|
|
// 树形DP
|
|
|
void dfs(int u) {
|
|
|
st[u] = 1;
|
|
|
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int v = e[i]; // 子节点最好设置为v,不要使用j,因为j一般后面会参于循环用的变量,节约资源
|
|
|
if (st[v]) continue;
|
|
|
dfs(v); // 因为父亲需要使用子树的信息来更新自己的信息,所以,必须先递归子树,才能使用子树提供的信息,子树提供的信息,保存在f[v][1~k]中
|
|
|
|
|
|
// 枚举体积 (u的所有可能体积)
|
|
|
/*
|
|
|
本来是三维的状态,f[x][i][j],表示以x为根的子树,的前i个子节点子树中选,总体积最大为j的所有集合,
|
|
|
每次去循环以x节点为跟的子树,并循环体积,一个子树相当于一个组,一组内不同方案,相当于选择不同体积,
|
|
|
只看后面两个[i] [j]代表的是在前i个组中选,总体积不超过j的所有集合,属性max,然后还要枚举每一组内,分配多少体积,才能求出最大值
|
|
|
所以f[x] [i] [j] = max ( f[x] [i] [j],f[x] [i-1] [j-k] + f[y] [yi] [k])
|
|
|
然后进行优化,由于每次都用到上一维的状态,和子树y最后yi的状态,所以可以把第二维优化变成
|
|
|
f[x] [j] = max(f[x] [j] , f[x] [j-k] + f[y] [k])
|
|
|
|
|
|
是因为优化了一维,所以倒过来算了
|
|
|
*/
|
|
|
for (int j = m; j >= 0; j--)
|
|
|
// 枚举决策 (子节点v中分配k个体积,需要给u->v留一个,v子树中就少1个,k<j)
|
|
|
for (int k = 0; k < j; k++)
|
|
|
// f[u][j - 1 - k]:让u从其它子树中去查找,在空间j-1-k的限定下的最大价值
|
|
|
// f[v][k]+w[i]:在v子树中,资源上限是k的情况下,返回的最大数量,加上u->v这边条上的苹果数w[i]
|
|
|
f[u][j] = max(f[u][j], f[u][j - 1 - k] + f[v][k] + w[i]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
// 初始化
|
|
|
memset(h, -1, sizeof h);
|
|
|
cin >> n >> m;
|
|
|
|
|
|
// 读入n-1条边
|
|
|
int a, b, c;
|
|
|
for (int i = 1; i < n; i++) {
|
|
|
cin >> a >> b >> c;
|
|
|
add(a, b, c), add(b, a, c); // 只能是无向图,因为没说谁离根更近
|
|
|
}
|
|
|
dfs(1); // 已知根是1号点
|
|
|
cout << f[1][m] << endl; // DP:从根出发,最大限制是m的情况下,可以取得的最大值
|
|
|
return 0;
|
|
|
} |