首页 > 代码库 > hdu1561 树形dp+背包

hdu1561 树形dp+背包

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561

思路:树形dp+01背包 //看注释可以懂

用vector建树更简单。

代码:

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define ll long long
const int maxn=2e2+5;
const int INF=0x3f3f3f3f;
///dp[i][j] 表示以i为跟节点的树,选其中的j个节点可以达到的最大值
int dp[maxn][maxn];
vector<int>v[maxn];
int N,M,x,a[maxn];

void dfs(int n,int m)
{
    dp[n][1]=a[n];
    int len=v[n].size();
    for(int i=0; i<len; i++)  ///01背包第一层循环
    {
        if(m>1) dfs(v[n][i],m-1);
        for(int j=m-1; j>=1; j--)  ///第二层循环,相当于背包的重量,-1的原因是至少有一个节点是根节点
            for(int k=1; k<=j; k++)  ///k是在第i棵树上选K个子节点
                dp[n][j+1]=max(dp[n][j+1],dp[n][j+1-k]+dp[v[n][i]][k]); ///+1的目的就是保证至少选一个节点是根节点 
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&N,&M) && N+M)
    {
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        for(int i=0; i<=N; i++) v[i].clear(); 
        for(int i=1; i<=N; i++)
        {
            scanf("%d%d",&x,&a[i]);
            v[x].push_back(i);
        }
        dfs(0,M+1);
        printf("%d\n",dp[0][M+1]);
    }
    return 0;
}

 

hdu1561 树形dp+背包