本题中很大不同点在于他给的是边的数值,而正常的树的问题是在节点上给值。那么我们采用边值下放点的做法,这样就是正常的树问题了。
那么对于某一个节点来说它保留j个节点所得到的最大苹果树取决于这j个节点来自于左边子树多少,来自右边子树多少。又因为他自身就有一个节点所以状态转移方程为:
dp[i][need] = max(dp[i][need], num_l+num_r+tree[i].val);
但是要注意对于第一个节点传递的时候需要传递q+1,因为别的节点都有父亲,所以他们本身也贡献一个树枝。但根节点没有,为了保证一致性所以传递q+1。
还有这题使用记忆化搜索最简单,因为使用单纯的状态转移的话对于转移的范围不靠控制,还得知道子树下面到底有多少个节点。
#include <bits/stdc++.h>
using namespace std;
const int maxnf = 100+10;
const int maxn = 100*2+10;
struct tree{
int l, r;
int val;
} tree[maxnf];
int dp[maxnf][maxnf];
//使用链式前向星去表示一棵树。
int lt[maxn], nt[maxn], ed[maxn], nm[maxn];
int cnt = 0;
int n, q;
void addd(int x, int y, int val) {
ed[++cnt] = y;
nt[cnt] = lt[x];
lt[x] = cnt;
nm[cnt] = val;
}
void init(int x, int fa) {
for (int i=lt[x];i;i = nt[i]) {
int y = ed[i];
if (y==fa) continue;
if (!tree[x].l) tree[x].l = y;
else tree[x].r = y;
tree[y].val = nm[i];
init(y, x);
}
}
//状态转移方程:dp[i][j] = max(dp[l][k], dp[r][j-k-1])+tree[i].val;
int dfs(int i, int need) {
int l = tree[i].l;int r = tree[i].r;
if (i==0) return 0;
if (dp[i][need]!=0) return dp[i][need];
for (int k=0;k<need;k++) {
int num_l = dfs(tree[i].l, k);
int num_r = dfs(tree[i].r, need-k-1);
dp[i][need] = max(dp[i][need], num_l+num_r+tree[i].val);
}
return dp[i][need];
}
int main() {
int x, y, val;
cin>>n>>q;
for (int i=1;i<n;i++) {
cin>>x>>y>>val;
addd(x, y, val);
}
//将边值变成点值,方便后面的处理。
init(1, 0);
cout<<dfs(1, q+1);
return 0;
}

京公网安备 11010502036488号