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; }