hdu1561--H - ACboy needs your help(树形dp)

H - ACboy needs your help
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit   Status

 

Description

ACboy has N courses this term, and he plans to spend at most M days on study.Of course,the profit he will gain from different course depending on the days he spend on it.How to arrange the M days for the N courses to maximize the profit?  
 

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers N and M, N is the number of courses, M is the days ACboy has.  
Next follow a matrix A[i][j], (1<=i<=N<=100,1<=j<=M<=100).A[i][j] indicates if ACboy spend j days on ith course he will get profit of value A[i][j].  
N = 0 and M = 0 ends the input.  
 

Output

For each data set, your program should output a line which contains the number of the max profit ACboy will gain.  
 

Sample Input

     
     
2 2 1 2 1 3 2 2 2 1 2 1 2 3 3 2 1 3 2 1 0 0
 

Sample Output

     
     
3 4 6
 

树形dp第一题啊

题目给出的依赖关系,可以组成几个树,在虚拟一个root,节点0,这样把所有的点连接到一起

树形dp中,数组dp[i][j]表示,对于第i个节点来说,选取j个城市,可以达到的最大值,建树完成后,dfs,递归到叶子节点,dp[叶子][1] = 叶子的权值,其他的都是0,然后回溯上来,回到父节点,dp[i][j] = max( dp[i][j],dp[i][j-k]+dp[v][k] ) v表示孩子节点,k表示在整个以v为根节点的子树中选取k个城市,那么在以i为根节点的城市只能选取j-k个了,这样近似于将i的每一个子节点都看做分组背包中的一个组,进行分组背包的操作,来得到dp[i][j] (1<=j <= m)的最大的权值,然后逐层回溯。

注意1,增加的总的根root,所以要求的城市数m应该再加上1.

注意2,因为存在依赖关系,所以dp[i][1]一定是i节点的权值,之后的才是子节点可以改变的权值,所以dp[i][j],j应该大于等于2,而且k一定要小于j,留下的一个位置放第i个节点

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct node{
    int v ;
    int next ;
} edge[1000000] ;
int head[300] , p[300] , cnt ;
int dp[300][300] ;
int n , m ;
void add(int u,int v)
{
    edge[cnt].v = v ;
    edge[cnt].next = head[u] ;
    head[u] = cnt++ ;
}
void dfs(int u)
{
    int i , v , j , k ;
    dp[u][1] = p[u] ;
    for(i = head[u] ; i != -1 ; i = edge[i].next)
    {
        v = edge[i].v ;
        dfs(v);
        for(j = m ; j >= 2 ; j--)
        {
            for(k = 0 ; k < j ; k++)
                dp[u][j] = max( dp[u][j], dp[u][j-k]+dp[v][k] );
        }
    }
}
int main()
{
    int u , v , i ;
    while( scanf("%d %d", &n, &m)!=EOF )
    {
        if(n == 0 && m == 0) break;
        memset(head,-1,sizeof(head));
        memset(dp,0,sizeof(dp));
        p[0] = cnt = 0 ;
        for(i = 1 ; i <= n ; i++)
        {
            scanf("%d %d", &u, &v);
            p[i] = v ;
            add(u,i);
        }
        m++ ;
        dfs(0);
        printf("%d\n", dp[0][m]);
    }
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值