• BZOJ1017 树形DP


    1017: [JSOI2008]魔兽地图DotR

    Time Limit: 30 Sec  Memory Limit: 162 MB
    Submit: 2308  Solved: 919
    [Submit][Status][Discuss]

    Description

      DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA
    (Defense of the Ancients) Allstars。DotR里面的英雄只有一个属性——力量。他们需要购买装备来提升自己的
    力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力
    量值之和。装备分为基本装备和高级装备两种。基本装备可以直接从商店里面用金币购买,而高级装备需要用基本
    装备或者较低级的高级装备来合成,合成不需要附加的金币。装备的合成路线可以用一棵树来表示。比如,Sange
    and Yasha的合成需要Sange,Yasha和Sange and Yasha Recipe Scroll三样物品。其中Sange又要用Ogre Axe, Belt
     of Giant Strength和 Sange Recipe Scroll合成。每件基本装备都有数量限制,这限制了你不能无限制地合成某
    些性价比很高的装备。现在,英雄Spectre有M个金币,他想用这些钱购买装备使自己的力量值尽量高。你能帮帮他
    吗?他会教你魔法Haunt(幽灵附体)作为回报的。

    Input

      第一行包含两个整数,N (1 <= n <= 51) 和 m (0 <= m <= 2,000)。分别表示装备的种类数和金币数。装备
    用1到N的整数编号。接下来的N行,按照装备1到装备n的顺序,每行描述一种装备。每一行的第一个非负整数表示这
    个装备贡献的力量值。接下来的非空字符表示这种装备是基本装备还是高级装备,A表示高级装备,B表示基本装备
    。如果是基本装备,紧接着的两个正整数分别表示它的单价(单位为金币)和数量限制(不超过100)。如果是高
    级装备,后面紧跟着一个正整数C,表示这个高级装备需要C种低级装备。后面的2C个数,依次描述某个低级装备的
    种类和需要的个数。

    Output

      第一行包含一个整数S,表示最多可以提升多少点力量值。

    Sample Input

    10 59
    5 A 3 6 1 9 2 10 1
    1 B 5 3
    1 B 4 3
    1 B 2 3
    8 A 3 2 1 3 1 7 1
    1 B 5 3
    5 B 3 3
    15 A 3 1 1 5 1 4 1
    1 B 3 5
    1 B 4 3

    Sample Output

    33
     
    //先标明参考来源 http://hzwer.com/5198.html
     
    大体上就是好几个子树,然后对子树进行DP的样子,没有建立虚拟根节点,也是用子节点的状态去更新父节点的状态,细节见代码。
     
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int inf=1e9;
    using namespace std;
    int n,m,cnt,tot,ans;
    int P[55],L[55],M[55];
    int f[55][105][2005];
    int g[55][2005],h[55][2005];
    char ch[5];
    int last[55],deg[55];
    struct data{int to,next,v;}e[20008];
    void insert(int u,int v,int w) {
        e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
        ++deg[v];
    }
    void dp(int x) {
        if(!last[x]) {   //倘若这个就是基本装备,那么记录一下其f数组的值就可以直接return了。
            L[x]=min(L[x],m/M[x]);
            for(int i=0;i<=L[x];++i)
                for(int j=i;j<=L[x];++j)
                f[x][i][j*M[x]]=(j-i)*P[x];//f[i][j][k],第i个物品,有j件用于上层的合成,花费金钱k所能获得的最大力量
            return;
        }
        L[x]=inf;
        for(int i=last[x];i;i=e[i].next) {  
            dp(e[i].to);  //向下对其子节点进行处理。
            L[x]=min(L[x],L[e[i].to]/e[i].v);  //更新数量
            M[x]+=e[i].v*M[e[i].to];//更新花费
        }
        L[x]=min(L[x],m/M[x]);
        memset(g,-0x3f3f3f3f,sizeof(g));
        g[0][0]=0;//表示x的前i个儿子的子树,花费j的钱,所能获得的最大力量
        for(int l=L[x];l>=0;--l) {   //此处开始处理父节点出的f数组值,枚举合成复合装备的数量,***注意for循环的方向是由L[x]到0***。
            int tot=0;
            for(int i=last[x];i;i=e[i].next) {
                ++tot;//这一行和上一行就相当于枚举每个基本装备
                for(int j=0;j<=m;++j)     //两个for的原因是因为花费不一定全部用完
                    for(int k=0;k<=j;++k)
                    g[tot][j]=max(g[tot][j],g[tot-1][j-k]+f[e[i].to][l*e[i].v][k]);
            }
            for(int j=0;j<=l;++j)//***此处for循环的方向没有影响***
                for(int k=0;k<=m;++k)
                f[x][j][k]=max(f[x][j][k],g[tot][k]+P[x]*(l-j));  //对f进行更新
        }
    }
    int main(){
        int x;
        memset(f,-0x3f3f3f3f,sizeof(f));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) {
            scanf("%d%s",&P[i],ch);
            if(ch[0]=='A') {
                scanf("%d",&x);
                while(x--) {
                        int v,num;
                    scanf("%d%d",&v,&num);
                    insert(i,v,num);
                }
            }
            else scanf("%d%d",&M[i],&L[i]);
        }
        for(int x=1;x<=n;++x) {
            if(!deg[x]) {
                dp(x);
                ++tot;
                for(int i=0;i<=m;++i)
                    for(int j=0;j<=i;++j)
                    for(int k=0;k<=L[x];++k)
                    h[tot][i]=max(h[tot][i],h[tot-1][j]+f[x][k][i-j]);
            }
        }
        for(int i=0;i<=m;++i)
            ans=max(ans,h[tot][i]);
        printf("%d
    ",ans);
    }
  • 相关阅读:
    Springboot中使用Interceptor(拦截器)
    八大排序之冒泡排序
    八大排序之快速排序
    mysql 用户的增删改与授权
    基于Java8开发接口时,处理Java8中的日期
    Springboot中Filter的使用
    正则校验日期,不考虑闰年和闰月
    正则校验时间,24小时制
    记一下mybatis中foreach循环遇到的一个小问题
    sqlserver中一条语句执行查询与更新
  • 原文地址:https://www.cnblogs.com/mfys/p/6926794.html
Copyright © 2020-2023  润新知