3 2 0 1 0 2 0 3 7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2 0 0
5 13
链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561
做法:设一个0节点,自身价值是0,dp[i][j]表示第i个节点,取了j个节点后的价值。因为先取父亲才能取儿子,所以要从dp[i][1] 开始转移。把子节点的状态转移到父亲节点。
因为和分组背包一样,子节点不能重复更新父亲节点,所以外层循环父节点状态,从大到小,内层循环子节点状态。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <malloc.h> #include <ctype.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <stack> #include <queue> #include <vector> #include <deque> #include <set> #include <map> #define INF 999999999 #define eps 0.00001 #define LL __int64d #define pi acos(-1.0) vector<int> son[210]; int dp[210][210]; int val[210]; int n,m; void dfs(int nw) { //dp[nw][0]=0; dp[nw][1]=val[nw]; for(int i=0;i<son[nw].size();i++) { dfs(son[nw][i]); int ss=son[nw][i]; for(int k=m;k>=1;k--) { if(dp[nw][k]!=-1) { for(int j=1;j<=m;j++) { if(dp[ss][j]==-1) break; dp[nw][j+k]=max(dp[ss][j]+dp[nw][k],dp[nw][j+k]); } } } } } int main() { while(scanf("%d%d",&n,&m),n||m) { memset(dp,-1,sizeof dp); for(int i=0;i<=n;i++) { son[i].clear(); } val[0]=0; for(int i=1;i<=n;i++) { int a,b; scanf("%d%d",&a,&val[i]); son[a].push_back(i); } dfs(0); printf("%d\n",dp[0][m+1]); } return 0; }