题意:
求从根节点出发走K步经过的结点权值和最大
分析:
很容易想到dp【i】【j】表示i为根走j步的最优解,对于所有儿子结点跑一个01背包就ok
这时候会发现对于当前状态从i出发走j步回到i节点和不回到i节点对于状态转移是不一样的
所以加一维表示是否回到根节点(0----不回到 1-----回到)
那么转移方程:
dp[u][j][0]=max(dp[u][j][0],dp[u][j-k][1]+dp[v][k-1][0]);
if(k>=2)
dp[u][j][0]=max(dp[u][j][0],dp[u][j-k][0]+dp[v][k-2][1]);
dp[u][j][1]=max(dp[u][j][1],dp[u][j-k][1]+dp[v][k-2][1]);
k-1/k-2 是从根结点到当前儿子结点的花费
ACcode:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#define maxn 205
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,tmp;
struct N{
int to,next;
}my[maxn<<1];
int dp[maxn][maxn<<1][2];
int head[maxn],tot;
void init(){
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
tot=0;
}
void add(int u,int v){
my[tot].to=v;
my[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int fa){
for(int i=head[u];i!=-1;i=my[i].next){
int v=my[i].to;
if(v==fa)continue;
dfs(v,u);
for(int j=m;j>=1;--j){
for(int k=1;k<=j;++k){
dp[u][j][0]=max(dp[u][j][0],dp[u][j-k][1]+dp[v][k-1][0]);
if(k>=2){
dp[u][j][0]=max(dp[u][j][0],dp[u][j-k][0]+dp[v][k-2][1]);
dp[u][j][1]=max(dp[u][j][1],dp[u][j-k][1]+dp[v][k-2][1]);
}
}
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
init();
for(int i=1;i<=n;++i){
scanf("%d",&tmp);
for(int j=0;j<=m;++j)
dp[i][j][0]=dp[i][j][1]=tmp;
}
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1);
cout<<max(dp[1][m][0],dp[1][m][1])<<'\12';
}
return 0;
}