Hdu 1011 Starship Troopers (DP_树形DP(背包))

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


题目大意:给一棵树,有n个顶点,n-1条边,每个顶有一些bugs,现在要用炸弹(就用炸弹吧)轰炸,一个炸弹最多炸死20只bug,如果某个地方为0只bug,可以滚到下一个节点去炸,n<=100,边m<=100


解题思路:比较简单的树形DP+背包。本题的依赖关系可以理解成树边,到达子节点必须先经过父节点,本质是一样的,建立起一棵树就开始如何进行dp,解题核心是搞清楚如何从子节点获取信息。

    一个子节点就可以返回m个状态,每个状态表示容量为j(j<=m)时炸最多的bug,而一个子节点中只可以选择一个状态进行转移,每个节点有若干个子节点,问题就转换为分组背包,几个子节点就是几个分组背包,体积是选几个地点,价值为Boos的可能性。本题要特判m为0时,直接输出0.

     状态转移方程: dp[v][1] = bug[v]; (v为叶子节点)

                          dp[v][j] = max(dp[v][j],dp[v][j-i] + dp[k][i] );(v为非叶子节点,j表示用户个数,i为容量,k为v的子节点,)
     算法复杂度O(sum(num[i],num[s])) (num[i]为某个节点的叶子子孙个数,num[s]为i的子节点的叶子子孙个数)


测试数据:

5 10
50 10
40 10
40 20
65 30
70 30
1 2
1 3
2 4
2 5

1 1
20 7

5 0
50 10
40 10
40 20
65 30
70 30
1 2
1 3
2 4
2 5

4 1
0 10
0 10
0 10
0 10
1 2
2 3
1 4

-1 -1


代码:

#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define MAX 110
#define max(a,b) (a)>(b)?(a):(b)


int val[MAX],need[MAX];
vector<int> tree[MAX];
int cnt,n,m,dp[MAX][MAX],vis[MAX];


void Tree_DP(int s){

    if (vis[s]) return ;
    vis[s] = 1;
	int i,j,k,tp,temp;


    for (i = need[s]; i <= m; ++i) 
		dp[s][i] = val[s];
    for (i = 0; i < tree[s].size(); ++i) {

        tp = tree[s][i];
        if (vis[tp]) continue;
        Tree_DP(tp);
        

        for (j = m; j >= need[s]; --j)
            for (k = 1; k + j <= m; ++k)
                if (dp[tp][k]) {

		            temp = dp[s][j] + dp[tp][k];
                    dp[s][j+k] = max(dp[s][j+k],temp);
                }
    }
}


int main()
{
    int i,j,k,a,b;


    while (scanf("%d%d",&n,&m),n + m != -2){
    
        for (i = 1; i <= n; ++i){

            scanf("%d%d",&need[i],&val[i]);
			tree[i].clear();
            need[i] = (need[i] + 19) / 20;
        }

            
        for (i = 1; i < n; ++i){

            scanf("%d%d",&a,&b);
			if (a < b)
            tree[a].push_back(b);
            else 
			tree[b].push_back(a);
        }
		

		if (m == 0) {

			printf("0\n");
			continue;
		}

        memset(dp,0,sizeof(dp));
        memset(vis,0,sizeof(vis));
        Tree_DP(1);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值