这是一个树上的背包转移。注意要用dp[i][j][k]表示第i个节点用了j的路程是否回到i节点,k=0表示回到i点,k=1表示不回到i点。那么实际上就是树上的一个背包转移。
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <string>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int inf = 0x3fffffff;
const int mmax =110;
struct node
{
int en;
int next;
}E[2*mmax];
int p[mmax],w[mmax],num;
int dp[mmax][210][2];
void init()
{
memset(p,-1,sizeof p);
num=0;
}
void add(int st,int en)
{
E[num].en=en;
E[num].next=p[st];
p[st]=num++;
}
int n,K;
bool vis[mmax];
void dfs(int u)
{
vis[u]=1;
for(int i=p[u];i+1;i=E[i].next)
{
int v=E[i].en;
if(!vis[v])
{
dfs(v);
for(int j=K;j>=0;j--)
{
for(int e=0;e<=K;e++)
{
if(j-e-2>=0 && dp[u][j-e-2][0]+1 && dp[v][e][0]+1)
{
dp[u][j][0]=max(dp[u][j][0],dp[u][j-e-2][0]+dp[v][e][0]);
}
if(j-e-1>=0 && dp[u][j-e-1][0]+1)
{
if(dp[v][e][0]+1)
dp[u][j][1]=max(dp[u][j][1],dp[u][j-e-1][0]+dp[v][e][0]);
if(dp[v][e][1]+1)
dp[u][j][1]=max(dp[u][j][1],dp[u][j-e-1][0]+dp[v][e][1]);
}
if(j-e-2>=0 && dp[u][j-e-2][1]+1 && dp[v][e][0]+1)
{
dp[u][j][1]=max(dp[u][j][1],dp[u][j-e-2][1]+dp[v][e][0]);
}
}
}
}
}
}
int main()
{
while(cin>>n>>K)
{
init();
memset(dp,-1,sizeof dp);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
dp[i][0][0]=dp[i][0][1]=w[i];
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
memset(vis,0,sizeof vis);
dfs(1);
int ans=0;
for(int i=0;i<=K;i++)
{
ans=max(ans,dp[1][i][0]);
ans=max(ans,dp[1][i][1]);
}
printf("%d\n",ans);
}
return 0;
}