树形DP——HDU 1011 Starship Troopers

HDU 1011 Starship Troopers

题目

http://acm.hdu.edu.cn/showproblem.php?pid=1011
作为星河战队的领导者,你被派去摧毁这些虫子的基地。

基地为一个个房间连成的树形结构,每个房间都被一些虫子占据,对应一定的大脑(分数)在房间里。为了尽快完成战斗,你不想等到部队人员清理房间后再前进到下一个房间,而是你必须在每个房间留下一些士兵来对抗里面的所有虫子。一个星舰士兵可以对抗20个虫子。由于你没有足够的士兵,你只能占用一些房间,让神经气体完成其余的工作(无法获得大脑)。计算最大所有可获得大脑的总和。

输入输出

输入:
N(房间个数)M(士兵个数)
N行,每行两个数,bugs[i](房间虫子数目)brain(房间大脑数目)
N-1行,每行两个数,room1 room2(room1和room2相连)
多组数据,-1,-1结束
输出:
最大获得大脑总和
多组数据

思路

dp[i][j]:第i个节点用去j个士兵获得的最大大脑数目
状态转移公式:dp[node][j]=max(dp[node][j],dp[node_son][l]+dp[node][j-l]);
树形DP:dfs

坑~

1.士兵个数M=0时,即使bugs=0,brains!=0,结果仍未0。
2.即使bugs=0不需要士兵消灭虫子也需要有士兵走过改路线。可设置叶子结点bugs=0为bugs=1。
3.两个房间连接的输入不一定是从父节点到子节点的,即需要存入无向图然后设置标志位实现树形的遍历。
4.见题目注释。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<iomanip>
#include<algorithm>
#include<numeric>
#include<functional>
#include<memory>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<vector>
#include<fstream>
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
const int MAX=0x7fffffff;
const long long LINF=0x3f3f3f3f3f3f3f3f;
const long long LMAX=0x7fffffffffffffff;
const double eps=1e-9;
const int Mod=100007;
const int Max=10000005;
using namespace std;
int N,M;
int bugs[102],brains[102];
int a[102][102];
int dp[102][102];
bool f[102];
vector<int> v[102];

void dfs(int node){
    f[node]=1; 

    int node_min;
    node_min=(bugs[node]+19)/20;
    for(int i=node_min;i<=M;++i){
        dp[node][i]=brains[node];
    }

    int son_nums,node_son,node_son_min;
    son_nums=v[node].size();
    for(int i=0;i<son_nums;++i){
        node_son=v[node][i];
        if(f[node_son]==0)
        {
            dfs(node_son);
            //for(int j=node_min;j<=M;++j){//不能从小到大,以为j大值有小值更新
            for(int j=M;j>=node_min;--j){
                //node_son_min=(bugs[node_son]+19)/20;
                //for(int l=node_son_min;j-l>=node_min;++l){//需要从1开始,以为node节点可以不取
                for(int l=1;j-l>=node_min;++l){
                        dp[node][j]=max(dp[node][j],dp[node_son][l]+dp[node][j-l]);
                }
            }    
        }

    }
}

int main() {
    freopen("data.in","r",stdin);
    cin.sync_with_stdio(false);
    cout.sync_with_stdio(false);
    while((cin>>N>>M)&&N!=-1&&M!=-1){
        for(int i=1;i<=N;++i){//init
            v[i].clear();
        }
        memset(dp,0,sizeof(dp));
        memset(f,0,sizeof(f));

        for(int i=1;i<=N;++i){//read
            cin>>bugs[i]>>brains[i];
        }
        int room1,room2;
        for(int i=0;i<N-1;++i){
            cin>>room1>>room2;
            v[room1].push_back(room2);
            v[room2].push_back(room1);
        }

        for(int i=1;i<=N;++i){//
            if(v[i].size()==1&&i!=1&&bugs[i]==0){//树形结构只有1--2时,1的size也是1 
                bugs[i]=1;
            }
        }

        if(M==0){//doit
            cout<<0<<endl;
        }else{ 
            dfs(1);
            cout<<dp[1][M]<<endl;
        }
    }

    fclose(stdin);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值