树形dp。
题意:
是有n个洞组成一棵树,你有m个士兵,你从1号房间开始攻打,每个洞有a个"bugs"和b的价值。你的一个士兵可以打20个"bugs",为了拿到这个洞的价值b你必须留下k个士兵消灭这个洞的所有"bugs"(k*20>="bugs"的数量,且留下的士兵不可以再去攻打其他的洞,且必须攻打了前面的洞才可以攻打后面的洞)。问你花费这m个士兵可以得到的最大价值是多少。
方程:
dp[p][j]表示到p处花费j所能得到的最大价值。
dp[p][j]=max(dp[p][j],dp[p][j-k]+dp[ son[p] ][ k ])
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=110;
bool vis[maxn];
vector<int>tree[maxn];
int cost[maxn],value[maxn];
int n,m;
int dp[maxn][maxn];
void dfs(int root){
vis[root]=true;
int temp=(cost[root]+19)/20;
for(int i=temp;i<=m;i++)
dp[root][i]=value[root];
for(int i=0;i<tree[root].size();i++){
int t=tree[root][i];
if(vis[t]) continue;
dfs(t);
for(int j=m;j>=temp;j--){
for(int k=1;k+temp<=j;k++){
dp[root][j]=max(dp[root][j],dp[root][j-k]+dp[t][k]);
}
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF && n!=-1&&m!=-1){
for(int i=0;i<maxn;i++) tree[i].clear();
memset(vis,false,sizeof(vis));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%d%d",&cost[i],&value[i]);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
tree[a].push_back(b);
tree[b].push_back(a);
}
if(m==0) cout<<0<<endl;
else{
dfs(1);
cout<<dp[1][m]<<endl;
}
}
return 0;
}