zoukankan      html  css  js  c++  java
  • [BZOJ 1017][JSOI2008]魔兽地图DotR(树形Dp)

    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(幽灵附体)作为回报的。

    Solution

    父节点依赖子节点的奇怪的树形Dp

    看黄学长的代码写的,一开始还写挂了,然后改呀改呀整个人有点凌乱

    tips都在注释里了,不过写这道题还是推荐不要看我的题解

    (vfk那个版本应该会快很多,但现在还没看懂QvQ)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #define Max(a,b) (a>b?a:b)
    #define Min(a,b) (a<b?a:b)
    #define INF 0x3f3f3f3f
    using namespace std;
    int n,m;
    int power[55],cost[55],limit[55],deg[55];
    int f[55][200][2005],g[55][2005],h[55][2005];
    int head[55],cnt=0,ans=0,num=0;
    bool vis[55];
    struct Node{
        int next,to,w;
    }Edges[3000];
    void addedge(int u,int v,int w)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
        Edges[cnt].w=w;
    }
    int Read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    void work(int x)
    {
        if(vis[x])return;
        vis[x]=1;
        if(head[x]==-1)//如果是叶子结点 
        {
            limit[x]=Min(limit[x],m/cost[x]);
            for(int j=0;j<=limit[x];j++)//f[编号][用于上层的个数][钱] 
            for(int i=j;i<=limit[x];i++)//第x个物品合成i个,其中j个用于上层
            {
                f[x][j][i*cost[x]]=(i-j)*power[x]; 
            }
            return;
        }
        limit[x]=INF;
        for(int i=head[x];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            work(v);
            limit[x]=Min(limit[x],limit[v]/Edges[i].w); 
            cost[x]+=Edges[i].w*cost[v];
        }
        limit[x]=Min(limit[x],m/cost[x]);
        memset(g,-INF,sizeof(g));
        g[0][0]=0;
        for(int l=limit[x];l>=0;l--)//枚举合成l个物品 
        {
            int tot=0;
            for(int i=head[x];~i;i=Edges[i].next)
            {
                tot++;
                int v=Edges[i].to;
                for(int j=0;j<=m;j++)//g[tot][j]:前tot个子树花费为j时获得的最大能量 
                for(int k=0;k<=j;k++)//在子树v上花费k时 
                g[tot][j]=Max(g[tot][j],g[tot-1][j-k]+f[v][l*Edges[i].w][k]);
            }
            for(int j=0;j<=l;j++)//l个物品中j个用于上层 
            for(int k=0;k<=m;k++)//花费k 
            f[x][j][k]=Max(f[x][j][k],g[tot][k]+power[x]*(l-j));
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        memset(f,-INF,sizeof(f));//注意不能赋值为0,有好多状态其实无法达到 
        n=Read();m=Read();
        for(int i=1;i<=n;i++)
        {
            power[i]=Read();
            int son;
            char c=getchar();
            while(c!='A'&&c!='B')c=getchar();
            if(c=='A')
            {
                son=Read();
                for(int j=1;j<=son;j++)
                {
                    int v,w;
                    v=Read();w=Read();
                    addedge(i,v,w);
                    deg[v]++;
                }
            }
            else 
            { 
                cost[i]=Read();
                limit[i]=Read();
            }
        }
        for(int x=1;x<=n;x++)
        {
            if(!deg[x])
            {
                work(x);
                num++;
                for(int i=0;i<=m;i++)
                for(int j=0;j<=i;j++)
                for(int k=0;k<=limit[x];k++)//h[num][i]:前num棵树花费为i
                {
                    h[num][i]=Max(h[num][i],h[num-1][j]+f[x][k][i-j]);
                    ans=Max(ans,h[num][i]);
                }
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    centos 7 服务器网卡做bond
    python 函数参数
    python 文件操作
    Linux 150命令之 文件和目录操作命令 cd pwd cp mv touch
    创建https证书
    Linux 150命令之 文件和目录操作命令 ls
    zabbix 2.2.2 安装部署
    NTP错误总结
    NTP时间服务器
    150命令之线上查询及帮助命令 man hellp
  • 原文地址:https://www.cnblogs.com/Zars19/p/6664831.html
Copyright © 2011-2022 走看看