题目:
http://acm.hdu.edu.cn/showproblem.php?pid=4276
题意:
给出一棵树,从1走到n,总时间为T,每走一条边需要花费一定时间,每个结点有一定价值,问在指定时间内回到T的能获取的最大价值。
思路:
先跑一次dfs,得到从1~n必走的路径,将这些路径值置0.
再一次dfs跑树形DP+分组背包,dp[i][j]: 表示到i点花费j时间得到的最大价值。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 105*2;
const int maxt = 505*2;
int n, T;
int dp[maxn][maxt];
int val[maxn];
int edge[maxn][maxn], tmpath[maxn];
void init()
{
memset(edge, -1, sizeof(edge));
memset(tmpath, -1, sizeof(tmpath));
memset(dp, 0, sizeof(dp));
}
void init_dfs(int u, int fa)
{
for(int i = 1; i <= n; ++i) {
if(edge[u][i] == -1) continue;
if(i == fa) continue;
tmpath[i] = u;
init_dfs(i, u);
}
}
void dfs(int u, int fa)
{
for(int i = 0; i <= T; ++i) dp[u][i] = val[u];
for(int i = 1; i <= n; ++i) {
int w = edge[u][i];
if(w == -1) continue;
if(i == fa) continue;
dfs(i, u);
w = 2*w;
for(int j = T; j >= w; --j) {
for(int k = 0; k <= j - w; ++k) {
dp[u][j] = max(dp[u][j], dp[i][k]+dp[u][j-k-w]);
}
}
}
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d%d", &n, &T)) {
init();
int u, v, w;
for(int i = 1; i < n; ++i) {
scanf("%d%d%d", &u, &v, &w);
edge[u][v] = edge[v][u] = w;
}
for(int i = 1; i <= n; ++i) {
scanf("%d", &val[i]);
}
init_dfs(n, n);
int pre = 1, cnt = 0, sum = val[1];
for(int i = tmpath[1]; ~i; i = tmpath[i]) {
sum += val[i];
cnt += edge[pre][i];
edge[pre][i] = edge[i][pre] = 0;
pre = i;
}
if(cnt > T) {
printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
continue;
}
T -= cnt;
dfs(1, 1);
printf("%d\n", dp[1][T]);
}
return 0;
}