题意:给你一棵树,树上的每个节点都有权值,从一个节点到另一个节点需要的步数是1,问从节点1开始,给你步数为K,问能得到的最大权值是多少。
定义dp[i][j][0]表示从节点i出发能走j步最后不回到i点能得到的最大权值是多少。
定义dp[i][j][1]表示从节点i出发能走j步最后回到i点能得到的最大权值是多少。
那么状态转移方法就可以知道了,如果还要回到u点,从节点u转移到节点v就需要两步,否则,就只需要一步,这是状态转移方程里面加一和加二的原因。
dp[u][i+2][0]=max(dp[u][i+2][0],dp[u][i-j][0]+dp[v][j][0]);
dp[u][i+2][1]=max(dp[u][i+2][1],dp[u][i-j][1]+dp[v][j][0]);
dp[u][i+1][1]=max(dp[u][i+1][1],dp[u][i-j][0]+dp[v][j][1]);
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=105;
struct Edge
{
int v;
Edge* nxt;
}memo[N*N],*cur,*adj[N];
int dp[N][N*2][2],n,K;
void dfs(int u,int fa)
{
for(Edge* it=adj[u];it;it=it->nxt)
{
int v=it->v;
if(v==fa) continue;
dfs(v,u);
for(int i=K;i>=0;i--)
{
for(int j=0;j<=i;j++)
{
dp[u][i+2][0]=max(dp[u][i+2][0],dp[u][i-j][0]+dp[v][j][0]);
dp[u][i+2][1]=max(dp[u][i+2][1],dp[u][i-j][1]+dp[v][j][0]);
dp[u][i+1][1]=max(dp[u][i+1][1],dp[u][i-j][0]+dp[v][j][1]);
}
}
}
}
void addEdge(int u,int v)
{
cur->v=v;
cur->nxt=adj[u];
adj[u]=cur++;
}
void init()
{
cur=memo;
memset(adj,0,sizeof(adj));
memset(dp,0,sizeof(dp));
}
int main()
{
while(scanf("%d%d",&n,&K)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%d",&dp[i][0][1]);
dp[i][0][0]=dp[i][0][1];
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
dfs(1,-1);
int res=0;
for(int i=0;i<=K;i++) res=max(res,dp[1][i][1]);
printf("%d\n",res);
}
return 0;
}