思路:
考虑树形dp。
我们设\(dp[i][j][0/1]\)表示在\(i\)为根的子树中花费\(j\)单位时间,最终回到/不必回到\(i\)的最大收益。
转移三种:
\(dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 2][0] + dp[y][k][1]);\)
\(dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 1][1] + dp[y][k][0]);\)
\(dp[x][j][1] = max(dp[x][j][1],dp[x][j - k - 2][1] + dp[y][k][1]);\)
搞定.
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int q=0,f=1;char ch = getchar();
while(!isdigit(ch)){
if(ch=='-')f = -1;ch=getchar();
}
while(isdigit(ch)){
q=q*10+ch-'0';ch=getchar();
}
return q*f;
}
const int maxn = 600;
struct edge {
int to;
int nxt;
}e[maxn << 1];
int cnt;
int head[maxn<<1];
inline void add_edge(int u,int v) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
inline void Add_edge(int u,int v) {
add_edge(u,v);
add_edge(v,u);
return;
}
int dp[maxn][maxn][2];
int m;int n;
int a[maxn];
inline void dfs(int x,int fa) {
for(int i = head[x];i;i=e[i].nxt) {
int y = e[i].to;
if(y == fa) continue;
dfs(y,x);
for(int j = m;j >= 2; --j) {
for(int k = 0;k <= m; ++k) {
if(j - k - 2 < 0) break;
dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 2][0] + dp[y][k][1]);
}
}
for(int j = m;j >= 1; --j) {
for(int k = 0;k <= m; ++k) {
if(j - k - 1 < 0) break;
dp[x][j][0] = max(dp[x][j][0],dp[x][j - k - 1][1] + dp[y][k][0]);
}
}
for(int j = m;j >= 2; --j) {
for(int k = 0;k <= m; ++k) {
if(j - k - 2 < 0) break;
dp[x][j][1] = max(dp[x][j][1],dp[x][j - k - 2][1] + dp[y][k][1]);
}
}
}
for(int i = m;i >= 1; --i) {
dp[x][i][0] = max(dp[x][i][0],dp[x][i - 1][0] + a[x]);
dp[x][i][1] = max(dp[x][i][1],dp[x][i - 1][1] + a[x]);
}
}
int main () {
#ifdef ONLINE_JUDGE
freopen("dostavljac.in","r",stdin);
freopen("dostavljac.out","w",stdout);
#endif
n = read(),m = read();
for(int i = 1;i <= n; ++i) {
a[i] = read();
}
for(int i = 1;i < n; ++i) {
int x = read(),y = read();
Add_edge(x,y);
}
dfs(1,0);
printf("%d\n",dp[1][m][0]);
return 0;
}