#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<iostream>
using namespace std;
#define maxn 6005
int dp[maxn][maxn],num[maxn],val[maxn];
vector<int>sons[maxn];
//num对于优化起了很大的作用,来记录当前结点子树中的叶子结点数目
void dfs(int rt){
dp[rt][0]=0;
for(int u=0;u<sons[rt].size();u++){
int s=sons[rt][u];
dfs(s);
num[rt]+=num[s];
for(int i=num[rt]-num[s]+1;i<=num[rt];i++) dp[rt][i]=-1000000; //要初始化为一个很大的负数
for(int i=num[rt];i>=1;i--){
for(int j=1;j<=num[s]&&j<=i;j++){
dp[rt][i]=max(dp[rt][i],dp[s][j]+dp[rt][i-j]+val[s]);
}
}
}
}
void init(){
for(int i=0;i<maxn;i++) sons[i].clear();
memset(val,0,sizeof(val));
memset(num,0,sizeof(num));
}
void print(){
for(int i=num[1];i>=0;i--)
if(dp[1][i]>=0)
{printf("%d\n",i);break;}
}
int main(){
int i,j,n,m,k,a,b;
while(~scanf("%d%d",&n,&m)){
init();
for(i=1;i<=n-m;i++){
scanf("%d",&k);
for(j=1;j<=k;j++){
scanf("%d%d",&a,&b);
sons[i].push_back(a);
val[a]=-b;
}
}
for(i=n+1;i<=n+m;i++){ //给每一个叶子结点加一个结点,用它来表示赚的钱,而其它点都表示需要支付的钱
scanf("%d",&val[i]);
num[i]=1;
sons[i-m].push_back(i);
}
dfs(1);
print();
}
return 0;
}原文:http://blog.csdn.net/crazy__c/article/details/44894439