dp[x][y]代表以x为根的子树..连接了y个终端用户(叶子)..所能获得的最大收益...
dp[x][ ]可以看成当根为x时..有个背包空间为0~m...每个空间上记录了到到达这个空间的最大收益..
典型的泛化背包问题...
Program:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<set>
#include<ctime>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define oo 100000007
#define ll long long
#define pi acos(-1.0)
#define MAXN 3005
using namespace std;
struct node
{
int x,y,c,next;
}line[MAXN];
int n,m,_next[MAXN],v[MAXN],dp[MAXN][MAXN],SubNum[MAXN];
void addline(int x,int y,int c,int m)
{
line[m].next=_next[x],_next[x]=m;
line[m].x=x,line[m].y=y,line[m].c=c;
return;
}
void dfs(int x)
{
int k=_next[x];
SubNum[x]=dp[x][0]=0;
if (!k) dp[x][1]=v[x],SubNum[x]=1;
else
while (k)
{
int i,j,y=line[k].y;
dfs(y);
SubNum[x]+=SubNum[line[k].y];
for (i=SubNum[x];i>=1;i--)
for (j=0;j<=SubNum[y] && j<=i;j++)
dp[x][i]=max(dp[x][i],dp[x][i-j]+dp[y][j]+line[k].c); //泛化背包转移
k=line[k].next;
}
return;
}
int main()
{
int i,num,t;
while (~scanf("%d%d",&n,&m))
{
num=0;
memset(_next,0,sizeof(_next));
memset(dp,-0x1f,sizeof(dp));
memset(v,0,sizeof(v));
memset(SubNum,0,sizeof(SubNum));
for (i=1;i<=n-m;i++)
{
scanf("%d",&t);
while (t--)
{
int A,C;
scanf("%d%d",&A,&C);
addline(i,A,-C,++num);
}
}
for (i=n-m+1;i<=n;i++) scanf("%d",&v[i]);
dfs(1);
for (i=m;i>=1;i--)
if (dp[1][i]>=0) break;
printf("%d\n",i);
}
return 0;
}