本题中很大不同点在于他给的是边的数值,而正常的树的问题是在节点上给值。那么我们采用边值下放点的做法,这样就是正常的树问题了。
那么对于某一个节点来说它保留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;
}