题意

  • 对于一个有n个结点的二叉树,根的编号一定为1,每条边有权值
  • 求保留q条边时,最多能获得多少权值
  • tip:分析样例可以知道,这棵树的根是必须保留的,“剪枝行为”一定是保留根含有根的子树

思路

  • 由于输入是无规律的输入每一条边,所以应当先建立起二叉树,从根开始深搜建树
  • 由于边权是较难处理的,我们发现可以把所有边权变为该条边所连的儿子的权值,把边权转换为点权,同时边转化为点,会多一个点,所以最终保留q条边会变为保留q+1个点
  • 建完这棵树后,可以进行动态规划,对每个结点考虑剩下多少个边,进行枚举
  • 表示i包含j个点(边)
  • 树形dp,dfs深搜即可,每次深搜记录当前结点和剩余结点数,从当前层迭代到下一层只需改变剩余结点数即可

代码

#include<bits/stdc++.h>
using namespace std;

/**
 * dp[i][j]表示i包含j个点(边)
 * dp[i][j]=dp[T[i].l][k]+dp[T[i].r][j-1-k];
 */


typedef struct node{
    int val;
    int l,r;
}tree;
tree T[200];
vector<int> g[150];
int v[150][150];
int dp[150][150];
int n,q;

void push_down(int x,int fa){
    for(auto i : g[x]){
        if(i==fa)continue;

        if(T[x].l==0) T[x].l=i;
        else T[x].r=i;

        T[i].val=v[x][i];            
        push_down(i,x);
    }
}
int dfs(int x,int rst){
    if(x==0) return 0;
    if(dp[x][rst]!=0) return dp[x][rst];
    for(int i=0;i<rst;i++){
        dp[x][rst]=max(dp[x][rst],dfs(T[x].l,i)+dfs(T[x].r,rst-1-i)+T[x].val);
    }
    return dp[x][rst];
}

int main(){
    cin >> n >> q;
    for(int i=1;i<n;i++){
        int a,b,c;
        cin >> a >> b >> c ;
        g[a].push_back(b);
        g[b].push_back(a);
        v[a][b]=v[b][a]=c;
    }
    push_down(1,0);
    // for(int i=1;i<=n;i++){
    //     cout << i << ' ' << T[i].val << ' ' << T[i].l << ' ' << T[i].r << endl;
    // }
    cout << dfs(1,q+1) << endl ;
    return 0;
}