zoukankan      html  css  js  c++  java
  • hdu4044 依赖背包变形 好题!

    由于不是求最大的可拦截的HP值,而是要将最小值最大化,那么就需要分配每个子树用的钱数以达到最小值最大化

    第一步解决如何分配钱使得结点u的子树中用了j元钱后可以拦截的HP最大,这就是变形的分组(依赖)背包,即枚举m元钱,在子树v用t元钱,在v之前的子树用j-t元钱

      用Max[v][j]数组记录u的前v个结点花j元钱可以拦截的最大HP,Max[v][j]=max{min( dp[v][t] , Max[v-i][j-t] )},第一维v可以压缩掉

    第二步考虑结点u上建立什么炮塔,用Max数组来求出dp[u][j]即可

    /*
    给定一棵树,m块钱,每个结点上可以建造k种(价格price,攻击力power)防御塔
    求可以阻拦的最大血量 
    dp[i][j]表示子树i中花费j元可以抵挡的怪物血量
     
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1050
    struct Edge{int to,nxt;}edge[maxn<<2];
    struct node{int k,price[100],power[100];}p[maxn];
    int n,m,head[maxn],tot,dp[maxn][210],flag[maxn];
    void init(){
        tot=0;
        memset(head,-1,sizeof  head);
        memset(flag,0,sizeof flag);
    }
    void addedge(int u,int v){
        edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
    }
    void dfs(int u,int pre){
        //init,每个点只能建立一个塔嘛 
        for(int j=m;j>=0;j--)
            for(int i=1;i<=p[u].k;i++)
                if(j>=p[u].price[i])
                    dp[u][j]=max(dp[u][j],p[u].power[i]);
        
        if(flag[u]==1&&u!=1)return;//叶子节点退出 
        
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v!=pre)dfs(v,u);
        }    
        
        //Max[i][j]表示给前i个儿子花费j元时可以拦截的最大hp,可压成滚动数组 
        int Max[210];
        memset(Max,0x3f,sizeof Max); 
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)continue;
            for(int j=m;j>=0;j--){//给子树v之前的子树用j元 
                int maxx=0; 
                for(int t=0;t<=j;t++)//给子树v用t元 
                    maxx=max(maxx,min(dp[v][t],Max[j-t]));//找出最优的分配方式 
                Max[j]=maxx;//记录 
            }
        }
    
        //最后Max数组表示给u的子树总共花i元可以拦截的最大HP 
        for(int j=m;j>=0;j--)
            for(int t=0;t<=j;t++)//给子树花费t,给自己花费j-t元 
                dp[u][j]=max(dp[u][j],dp[u][j-t]+Max[t]);
    //printf("%d
    ",u);
    //for(int i=1;i<=m;i++)
    //    printf("%d ",dp[1][i]);
    }
    int main(){
        int t,u,v;
        cin>>t;
        while(t--){
            init();
            scanf("%d",&n);
            for(int i=1;i<n;i++){
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
                flag[u]++;flag[v]++;
            }
            scanf("%d",&m);
            for(int i=1;i<=n;i++){
                scanf("%d",&p[i].k);
                for(int j=1;j<=p[i].k;j++)
                    scanf("%d%d",&p[i].price[j],&p[i].power[j]);
            }
            memset(dp,0,sizeof dp);
            dfs(1,0);
            printf("%d
    ",dp[1][m]);
        }    
    } 
  • 相关阅读:
    7/31 CSU-ACM2018暑期训练7-贪心
    树状数组
    洛谷 P2947 [USACO09MAR]向右看齐Look Up【单调栈】
    如何求先序排列和后序排列——hihocoder1049+洛谷1030+HDU1710+POJ2255+UVA548【二叉树递归搜索】
    HDU 1611 敌兵布阵【线段树模板】
    Poj 2112 Optimal Milking (多重匹配+传递闭包+二分)
    Hdu 5361 In Touch (dijkatrs+优先队列)
    Codeforces Round #Pi (Div. 2)
    Hdu 5358 First One (尺取法+枚举)
    Poj 3189 Steady Cow Assignment (多重匹配)
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10348262.html
Copyright © 2011-2022 走看看