按照常见树形背包定义状态:设dp[u][j]表示在以u为根的子树中,选择j个客户所能获得的最大收益。
状态转移:dp[u][j]=max(dp[u][j-k],dp[v][k]-w(u,v));
注意因为二维的是滚动数组,所以应该倒着循环。
#include <bits/stdc++.h> using namespace std; int n,m; struct littlestar{ int to; int nxt; int w; }star[6010]; int head[6010],cnt; void add(int u,int v,int w) { star[++cnt].to=v; star[cnt].nxt=head[u]; star[cnt].w=w; head[u]=cnt; } int money[3010]; int f[3010][3010]; int dfs(int u) { if(u>n-m){ f[u][1]=money[u]; f[u][0]=0; return 1; } f[u][0]=0; int sum=0; for(int i=head[u];i;i=star[i].nxt){ int v=star[i].to; int tmp=dfs(v); sum+=tmp; for(int j=sum;j>=0;j--){ for(int k=0;k<=min(j,tmp);k++){ f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-star[i].w); } } } return sum; } int main() { cin>>n>>m; for(int i=1;i<=n-m;i++){ int num; scanf("%d",&num); for(int j=1;j<=num;j++){ int v,w; scanf("%d%d",&v,&w); add(i,v,w); } } for(int i=n-m+1;i<=n;i++){ scanf("%d",&money[i]); } memset(f,0x9f,sizeof(f)); for(int i=0;i<=n;i++){ f[0][i]=0; } dfs(1); for(int i=m;i>=0;i--){ if(f[1][i]>=0){ cout<<i; return 0; } } }