题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1011
题目大意:n个洞组成一棵树,你有m个士兵,你从1号洞开始攻打,每个洞有a个"bugs"和b的价值。每个士兵可以打20个"bugs",求可得到的最大价值。
题目分析:因为只有攻打了a房间才能继续攻打b房间,所以是树形关系,除此之外都与背包类似。
代码参考:
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 109;
vector<int> v[N];
bool vis[N];
int dp[N][N], bug[N], val[N];//dp[i][j]表示用j个士兵占领以i为根节点的子树所能获得的最大值
int n, m;
void dfs(int cur)
{
vis[cur] = true;
int trooper = (bug[cur] + 19) / 20;
for(int i = trooper; i <= m; ++ i) {
dp[cur][i] = val[cur];
}
for(int i = 0; i < v[cur].size(); ++ i) {//遍历子节点
int son = v[cur][i];
if(vis[son]) continue;//访问过的房间不能再进去
dfs(son);//继续向下搜索
for(int j = m; j >= trooper; -- j) {
for(int k = 1; k <= j - trooper; ++ k) {
dp[cur][j] = max(dp[cur][j], dp[cur][j - k] + dp[son][k]);
}
}
}
}
int main()
{
int a, b;
while(~scanf("%d%d", &n, &m)) {
if(n == -1 && m == -1) break;
for(int i = 0; i <= n; ++ i) {
v[i].clear();
}
memset(dp, 0, sizeof(dp));
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; ++ i) {
scanf("%d%d", &bug[i], &val[i]);
}
for(int i = 1; i < n; ++ i) {
scanf("%d%d", &a, &b);
v[a].push_back(b);//建树
v[b].push_back(a);
}
if(m == 0) {
puts("0"); continue;
}
dfs(1);
printf("%d\n", dp[1][m]);//最后的答案为以1为根,花费m个士兵所能得到的最大值
}
return 0;
}