感觉自己在理清码代码思路上面还是有很大的不足
用树形dp练习一下。
我就卜把这题当作二叉树,直接套背包啦
记f(x, c),表示以x为根的子树保留c条枝最多能够留下多少苹果。
那么,分类讨论:
对于某个点把它保留的c条枝头分别分给它的每个子节点
也就是说让每个子节点用一定的价值给父亲一定的贡献。
价值怎么分配?? 这个问题有一点点模糊,不过它实际上是一个很熟悉的模型
相当于某个子节点可以任取代价,某个代价可以得到某种价值
这是多重背包的经典模型。
进一步考虑,化为直观的状态和方程。
题目要求是选一个点子树中的点那么这个点必须没有被剪
于是f(x,c) = max{f(x,k)+Σf(childi,xi)+val(edge)}, Σxi=c-k-1
至于不保留这个点的情况就是f(x,0),会被父亲考虑到
因为根节点一定会被选(剪不掉),所以这样设计状态正好合适。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define add_edge(a, b, c) nxt[++tot] = head[a], head[a] = tot, to[tot] = b, val[tot] = c
int n, q, tot;
int head[105], nxt[205], to[205], val[205], siz[105];
int f[105][105];
void dfs(int x) {
siz[x] = 1;
for (int i = head[x]; i; i = nxt[i]) {
dfs(to[i]);
siz[x] += siz[to[i]];
}
for (int i = head[x]; i; i = nxt[i]) {
for (int k = siz[x] - 1; k >= 0; --k) {
for (int j = 0; j < siz[to[i]]; ++j) {
if (j >= k) continue;
f[x][k] = max(f[x][k], f[x][k-j-1] + f[to[i]][j] + val[i]);
}
}
}
}
int main() {
scanf("%d%d", &n, &q);
for (int a, b, c, i = 1; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
add_edge(a, b, c);
}
dfs(1);
printf("%d", f[1][q]);
return 0;
}