题意:
给出一棵树,每个点有权值,要取得这个权值需要代价,通过父亲后才能到达儿子。问能量有限时获得的最大值
思路:
1. 树形DP,要特殊考虑 m = 0 的情况,
2. 注意你走过的所有叶子节点都必须留下一人,但是中间的节点可以不留人,即使叶子bugs为0.但是因为要收割possible,必须有 trooper
3. 用泛化背包优化了半天,无奈水平有限,一直WA,后来想想可能此题确实无法像论文中那样的有依赖背包的优化,因为 m = 0 这个奇葩的存在。
调试半天虽然优化无果,但是也进一步加深了对于树形动态规划的理解,一些边边角角还是有待于打磨。
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 110;
struct edge {
int v;
edge* next;
} *V[MAXN], ES[MAXN * 2];
int EC, dp[MAXN][MAXN], B[MAXN], P[MAXN];
void addedge(int u, int v)
{
ES[++EC].next = V[u];
V[u] = ES + EC; V[u]->v = v;
}
void initdata(int n)
{
for (int i = 1; i <= n; ++i)
{
scanf("%d %d", &B[i], &P[i]);
B[i] = (B[i] + 19) / 20;
}
EC = 0;
memset(V, 0, sizeof(V));
for (int i = 1; i < n; ++i)
{
int a, b;
scanf("%d %d", &a, &b);
addedge(a, b);
addedge(b, a);
}
memset(dp, 0, sizeof(dp));
}
void treedp(int u, int f, int vol)
{
if (vol <= 0)
return ;
dp[u][B[u]] = P[u];
for (edge* e = V[u]; e; e = e->next)
{
if (e->v == f)
continue;
treedp(e->v, u, vol - B[u]);
for (int i = vol; i >= B[u]; --i)
for (int j = 0; j <= i - B[u]; ++j)
dp[u][i] = max(dp[u][i], dp[u][i-j] + dp[e->v][j]);
}
if (dp[u][0] > 0)
{
dp[u][1] = max(dp[u][0], dp[u][1]);
dp[u][0] = 0;
}
}
int main()
{
int n, m;
while (scanf("%d %d", &n, &m))
{
if (n == -1 && m == -1)
break ;
initdata(n);
treedp(1, 0, m);
printf("%d\n", dp[1][m]);
}
return 0;
}