一看题目的第一反应就是背包问题。。不过这题是在树上
设dp[i][j]为第个节点在他及他的子树中选取j个用户的最大盈利
dp[i][j]=max(dp[i][j],dp[x][j-k]+dp[y][k]-a[i].value);(y为当前i遍历到的儿子)
初始化:dp[i][j]=-inf;dp[i][0]=0;
答案就是在dp[1][i]中寻找一个最大的i使得dp[1][i]>=0
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=3000+5;
int dp[MAXN][MAXN],v[MAXN];
int h[MAXN],cnt;
struct node
{
int next;
int to;
int value;
}a[MAXN];
void addvage(int x,int y,int z)
{
cnt++;a[cnt].next=h[x];a[cnt].to=y;a[cnt].value=z;h[x]=cnt;
}
int n,m;
int dfs(int x){
if(x>=n-m+1){dp[x][1]=v[x];return 1;}
int sum=1;
for(int i=h[x];i;i=a[i].next){
int y=a[i].to;
int xx=dfs(y);sum+=xx;
for(int j=sum;j;j--)
for(int k=1;k<=xx;k++)
if(j-k>=0)
dp[x][j]=max(dp[x][j],dp[x][j-k]-a[i].value+dp[y][k]);
}
return sum;
}
int main()
{
cin>>n>>m;
int k,c,a;
for(int i=1;i<=n-m;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++){
scanf("%d%d",&c,&a);
addvage(i,c,a);
}
}
for(int i=n-m+1;i<=n;i++)
scanf("%d",&v[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=-10086;
for(int i=1;i<=n;i++)
dp[i][0]=0;
dfs(1);
for(int i=m;i>=0;i--)if(dp[1][i]>=0){cout<<i;break;}
return 0;
}