题目大意:有一颗n个节点的树,每个节点上有一些数量的苹果,Wshxzt从1号节点出发,每经过一条边算走一步,问走k不最多可以吃掉多少苹果;
思路:树形dp,背包问题,设dp1[i][j]为从i节点出发,走j步然后回到i节点所能吃到的最多苹果树,dp2[i][j]为从i节点出发,走j步可能不回到i节点所能吃到的苹果树
对于dp1[i][j]由于必须回到i号节点,所以如果访问了i的某个儿子,则i到这个儿子的边走了两次,
对于dp2[i][j],由于不回到i节点,所以有两种情况,对于某个儿子节点v,可能最后在v的子树中,也可能在出v外其他的子树中,对于第一种情况,i->v的边走1次,第二种情况走两次;
状态转移方程:
dp1[s][j+2]=max(dp1[s][j+2],dp1[s][j-t]+dp1[v][t]);//回到i节点
dp2[s][j+1]=max(dp2[s][j+1],dp1[s][j-t]+dp2[v][t]);//不回到i节点,最后在以v为根的子树中;所以访问v前必须回到了i节点,也就是dp1[s][j-t];
dp2[s][j+2]=max(dp2[s][j+2],dp2[s][j-t]+dp1[v][t]);//不回到i节点,最后在v之外的其他子树种,所以访问v之后可能有到了其他子树种结束,也就是dp2[s][j-t];
代码如下;
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <functional>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#define LL long long
using namespace std;
int n,k;
int head[111],size,key[222],next[222];
int value[111];
int dp1[111][222];
int dp2[111][222];
void add(int u,int v){
key[size]=v;next[size]=head[u];head[u]=size++;
}
void solve(int s,int pa){
for(int i=0;i<=k;++i)dp1[s][i]=dp2[s][i]=value[s];
for(int i=head[s];~i;i=next[i]){
int v = key[i];
if(v==pa)continue;
solve(v,s);
for(int j=k;j>=0;--j){
for(int t = 0;t<=j;++t){
dp1[s][j+2]=max(dp1[s][j+2],dp1[s][j-t]+dp1[v][t]);
dp2[s][j+1]=max(dp2[s][j+1],dp1[s][j-t]+dp2[v][t]);
dp2[s][j+2]=max(dp2[s][j+2],dp2[s][j-t]+dp1[v][t]);
}
}
}
}
int main(){
while(cin>>n>>k){
size = 0 ;memset(head,-1,sizeof(head));
for(int i=1;i<=n;++i)cin>>value[i];
int u,v;
for(int i=1;i<n;++i){
cin>>u>>v;
add(u,v);add(v,u);
}
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
solve(1,0);
cout<<max(dp1[1][k],dp2[1][k])<<endl;
}
return 0;
}