首先看到题目的第一反应,就是边上的权值不好处理,感觉非常麻烦,仔细一看,可以把边pushdown,反正一个结点只有一个父亲,那么就把边的权值放到对应孩子结点上,那么就大功告成了。
用二维数组求解问题,确定状态,用dp[root][y]表示结点root保留y个点(下放完事了以后是点,点会比边多一个,最后求的时候加1就好了)
dp[root][y]由本身和左子树 右子树够成,左子树+右子树+本身应该是等于y个点
那么通过枚举左子树、右子树的所有可能,就可以完成
代码实现先跑一遍找到对应的孩子,再进行记忆化搜索dp
#include <bits/stdc++.h>
using namespace std;
const int N=105;
int dp[N][N];
int G[N][N];
int val[N];
vector <int> vec[N];
int n,q;
struct node
{
int l,r;
node(){l=r=0;}
}tree[N];
void pushdown(int root,int pre)
{
for(int i=0;i<vec[root].size();i++)
{
int to=vec[root][i];
if(to==pre) continue;
if(tree[root].l==0) tree[root].l=to;
else if(tree[root].r==0) tree[root].r=to;
pushdown(to,root);
val[to]=G[root][to];
}
}
int dfs(int root,int y)
{
int left=0,right=0;
if(dp[root][y]) return dp[root][y];
if(root==0) return 0;
int ans=0;
dp[root][1]=val[root];
for(int k=0;k<y;k++){
left=dfs(tree[root].l,k);
right=dfs(tree[root].r,y-1-k);
ans=max(ans,left+right+dp[root][1]);
}
dp[root][y]=ans;
return dp[root][y];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u][v]=G[v][u]=w;
vec[u].push_back(v);
vec[v].push_back(u);
}
pushdown(1,0);
printf("%d\n",dfs(1,q+1));
}


京公网安备 11010502036488号