刚开始我以为是比较熟悉的树形dp+背包,但一直wa,网上的代码是非递归的,看到我头晕,看了大牛的代码后才发现有Trick...
发下代码,给有同样问题的人参考下
/**//*
题意:给出一棵树,每个点有权值,要取得这个权值需要代价,通过父亲后才能到达儿子
问能量有限时获得的最大值
直接tree dp+背包
注意的是,每个点至少要有一个人,即使没有bug!
*/
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN=110;
const int INF=1000000000;
int n,m;
vector<int>G[MAXN];
int bug[MAXN],brain[MAXN];
bool vi[MAXN];
int dp[MAXN][MAXN];
void dfs(int u){
vi[u]=1;
for(int j=1;j<=m;j++)dp[u][j]=-INF;
dp[u][0]=0;
int t=(bug[u]+19)/20;
//if(!t&&brain[u])t=1; 这样写会错
/**//*
2 1
0 1
0 1
1 2
答案是2
上面那样写答案是1
*/
if(t<=m)dp[u][t]=brain[u];
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(vi[v])continue;
dfs(v);
for(int j=m;j>t;j--)
for(int k=1;j-k>=t;k++)
if(dp[u][j-k]!=-1&&dp[v][k]!=-1&&dp[u][j]<dp[u][j-k]+dp[v][k])
dp[u][j]=dp[u][j-k]+dp[v][k];
}
//一定要有这一句,占领父亲取得brain,至少要有一个人!
//虽然不用攻击bug,所以这个人可以用来访问儿子
//不需要人就能获得brain,显然不行
if(dp[u][0]>0){
dp[u][1]=max(dp[u][1],dp[u][0]);
dp[u][0]=0;
}
}
int main(){
int a,b;
while(scanf("%d%d",&n,&m),n!=-1){
for(int i=1;i<=n;i++){
scanf("%d%d",&bug[i],&brain[i]);
G[i].clear();
}
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
G[a].push_back(b);
G[b].push_back(a);
}
memset(vi,0,sizeof(vi));
dfs(1);
int ans=0;
for(int j=1;j<=m;j++)
ans=max(ans,dp[1][j]);
printf("%d\n",ans);
}
return 0;
}