hdu 1561 The more, The Better(树形dp)

The more, The Better

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1561

解题思路:

依赖背包 -> 树形dp 
题意大意: 

给你一个树形结构,问最多拿max个城堡,能获得的价值最大,拿下面时一定也要先拿上面的。 
算法思想: 
定义状态dp[i][j] : 当前i节点及其子树下最多选择j个城市的最大值为dp[i][j];

我们考虑到特殊状态:i节点下没有孩子那么dp[i][2,3,4,5...]均为-1(因为多选总比少选好,并且选择完后城市总是有剩余) 

1. 判断当前节点P有没有孩子,如果有则令当前节点的孩子为P重复(1)操作,如果没有则到(2)操作; 

2. 将当前节点P的状态更新到期父节点上, 

更新操作为dp[P'father][i] = max(dp[P'father][i], dp[P'father][j]+dp[P][k])    (j + k = i ,j>0,k>0,2<=i<=m,对于每一个i遍历每一种(j,k)组合) 
这里的dp[P'father][j] j个城市一定是没有包括P城市的其他j个城市的最大值  

直到遍历到root节点即可(dp[0][i]) 

3.输出dp[0][m]
 
7 4 
2 2 
0 1 
0 4 
2 1 
7 1 
7 6 
2 2 
 [i]:v 表示 第i个节点的价值为v; [0]root没有价值相当于[0]:0 
                   [0]root 
                 /         \ 
            [2]:1          [3]:4 
         /    |   \    
   [1]:2   [4]:1   [7]:2 
                  /     \ 
                [5]:1  [6]:6 

AC代码:

#include <bits/stdc++.h>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 205;

vector<int> v[maxn];
int dp[maxn][maxn];
int n,m;

void dfs(int father){
    for (int i = 0; i < v[father].size(); i++){
        int child = v[father][i];//子节点
        if(v[child].size() > 0)
            dfs(child);
        for(int j = m; j > 1; j--){//保证从父节点开始,至少取j个城市,j>1 至少包括了这个父节点
            for(int k = 1; k < j; k++){//遍历每一种 k + j-k == j组合
                dp[father][j] = max(dp[father][j] ,dp[father][k] +  dp[child][j-k]);
            }
        }
    }
}

int main(){
    while(scanf("%d%d",&n,&m),n+m){
        for(int i = 0; i <= n; i++)
            v[i].clear();
        m++;//因为数据给出的是森林,我们加入一个root节点,因此相当于允许多拿一个城市。
        memset(dp,0,sizeof(dp));
        for(int i = 1; i <= n ; i++){
            int a,b;
            scanf("%d%d",&a,&b);
            v[a].push_back(i);
            for(int j = 1; j <= m; j++)
                dp[i][j] = b;       //初始化时,每个节点,所有状态都是拿自己一个
        }
        dfs(0);
        printf("%d\n",dp[0][m]);
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值