链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561
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
思路:有题目可知这是一棵根为0的树,那么结合树形DP的知识我们易知这是一个树上的分组背包问题,那么就很容易解出来了。只是要0和非0的情况,因为如果是非0的情况,那么本身是必须选入的(以i点为根取j个点的时候必须取入i点,这应该是显而易见的)。而如果是0,本身则不可以选入,那么同样是背包,条件改一下就OK。
dp[u][j]表示以u为根的树取j个数的最大权值 那么最后的答案就是dp[0][m]
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 210 struct Edge { int v,next; } edge[N<<1]; int head[N]; int cnt,n,m; int dp[N][N]; void init() { cnt=0; memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); } void addedge(int s,int e) { edge[cnt].v=e; edge[cnt].next=head[s]; head[s]=cnt++; } void dfs(int u) { for(int i=head[u]; i!=-1; i=edge[i].next) { int v=edge[i].v; dfs(v); if(u==0) { for(int l=m; l>=0; l--) for(int k=1; k<=l; k++) dp[u][l]=max(dp[u][l],dp[u][l-k]+dp[v][k]); } else { for(int l=m; l>1; l--) for(int k=1; k<l; k++) dp[u][l]=max(dp[u][l],dp[u][k]+dp[v][l-k]); } } } int main() { int s,v; while(~scanf("%d %d",&n,&m)&&(n+m)) { init(); for(int i=1; i<=n; i++) { scanf("%d %d",&s,&v); addedge(s,i); dp[i][1]=v; } dfs(0); printf("%d\n",dp[0][m]); } return 0; }