You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

59 lines
2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}