思路:
树形dp+记忆化搜索
先把边的权值转移到节点上
状态:dp[i][j]表示以i为根节点的子树中选取j个节点保留(包括自身)的最大苹果数
目标状态:dp[1][q+1]
初始状态:dp[i][0]=0(1<=i<=n)
dp[i][m]=w[i](i is a leaf, m can be any number)
状态转移:dp[i][j]=w[i]+max(dp[ls[i]][k]+dp[rs[i]][j-1-k])(0<=k<j)
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=105; struct edge{ int to,w,next; }edge[N*N]; int head[N]; int dp[N][N]; int w[N]; int ls[N],rs[N]; int cnt=0; void add_edge(int u,int v,int w){ edge[cnt].to=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int o,int u){ bool f=true; for(int i=head[u];~i;i=edge[i].next){ if(edge[i].to!=o){ w[edge[i].to]=edge[i].w; if(f)ls[u]=edge[i].to,f=false; else rs[u]=edge[i].to; dfs(u,edge[i].to); } } } int DFS(int u,int m){ if(m==0)return 0; if(dp[u][m]!=-1)return dp[u][m]; if(ls[u]==0&&rs[u]==0)return w[u]; dp[u][m]=0; for(int i=0;i<m;i++){ dp[u][m]=max(dp[u][m],DFS(ls[u],i)+DFS(rs[u],m-i-1)); } dp[u][m]+=w[u]; return dp[u][m]; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,q,u,v,w; mem(head,-1); mem(dp,-1); cin>>n>>q; for(int i=1;i<n;i++){ cin>>u>>v>>w; add_edge(u,v,w); add_edge(v,u,w); } dfs(0,1); cout<<DFS(1,q+1)<<endl; return 0; }