先描述一下状态;d[ 0 ][ root ][ j ]表示root节点不需回到root有j点能量可用最多能吃几个苹果;d[ 1 ][ root ][ j ]表示root节点必须需回到root有j点能量可用最多能吃几个苹果;
状态转移就很清晰了见代码;
#include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 105; struct node{ int to,val; node(int x=0,int y=0):to(x),val(y){} }a[maxn]; int n,k,w[maxn],d[2][maxn][maxn*2],temp[2][maxn*2]; vector<int> G[maxn]; void solve(int root,int f){ for(int i=0;i<=k;i++) d[0][root][i] = d[1][root][i] = w[root]; for(int i=0;i<G[root].size();i++){ int v = G[root][i]; if(v==f) continue; solve(v,root); for(int i=0;i<=k;i++) { temp[0][i]=d[0][root][i]; temp[1][i]=d[1][root][i]; } for(int i=1;i<=k;i++) for(int j=1;j<=i;j++){ d[0][root][i] = max(d[0][root][i],temp[1][i-j]+d[0][v][j-1]); if(j > 1){ d[0][root][i] = max(d[0][root][i],temp[0][i-j]+d[1][v][j-2]); d[1][root][i] = max(d[1][root][i],temp[1][i-j]+d[1][v][j-2]); } } } } int main() { while(scanf("%d %d",&n,&k)==2){ for(int i=1;i<=n;i++){ scanf("%d",&w[i]); } for(int i=1;i<=n;i++) G[i].clear(); for(int i=1;i<n;i++){ int x,y; scanf("%d %d",&x,&y); G[x].push_back(y); G[y].push_back(x); } solve(1,-1); printf("%d\n",d[0][1][k]); } return 0; }