首先看到题目的第一反应,就是边上的权值不好处理,感觉非常麻烦,仔细一看,可以把边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)); }