zoukankan      html  css  js  c++  java
  • JSOI 2008 魔兽地图

    题目描述

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

    输入输出格式

    输入格式:
    第一行包含两个整数,N (1 <= n <= 51) 和 m (0 <= m <= 2,000)。分别表示装备的种类数和金币数。装备用1到N的整数编号。

    接下来的N行,按照装备1到装备n的顺序,每行描述一种装备。

    每一行的第一个非负整数表示这个装备贡献的力量值。

    接下来的非空字符表示这种装备是基本装备还是高级装备,A表示高级装备,B表示基本装备。如果是基本装备,紧接着的两个正整数分别表示它的单价(单位为金币)和数量限制(不超过100)。如果是高级装备,后面紧跟着一个正整数C,表示这个高级装备需要C种低级装备。后面的2C个数,依次描述某个低级装备的种类和需要的个数。

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

    输入输出样例

    输入样例#1: 复制
    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
    输出样例#1: 复制
    33


    //By Monster_Qi
    #include<bits/stdc++.h>
    
    using namespace std;
    const int MAXM = 2005;
    const int MAXN = 55;
    const int inf = 0x3f3f3f3f;
    
    struct Edge{
        int nxt,to,val;
    }edge[MAXN*MAXN];
                    //dp[x][i][j]表示以x为节点,i个用于合成,花费j元的最大收益。 
    int n,m,head[MAXN],cnt,dp[MAXN][MAXN*2][MAXM]; 
    int L[MAXN],M[MAXN],war[MAXN];
       //L[x]表示以x为根的子树最多合成几个,M[x]表示以x为根的子树最大花费。 
    int ans[MAXM],f[MAXM]; //ans[x]表示花费x元的最大收益,f[x]表示花费x元的局部最大收益。 
    bool vis[MAXN],used[MAXN];
    
    inline void add(int bg,int ed,int w){
        edge[++cnt].to=ed;
        edge[cnt].val=w;
        edge[cnt].nxt=head[bg];
        head[bg]=cnt;
    }
    
    inline void dfs(int x){
        if(vis[x]) return;
        vis[x]=1;
        if(!head[x]){      //如果为叶节点。
            L[x]=min(L[x],m/M[x]);    
            for(register int i=L[x];i>=0;i--)     //枚举几个用来合成。 
                for(register int j=i;j<=L[x];j++)   //枚举一共买了几个。 
                    dp[x][i][M[x]*j]=war[x]*(j-i);
            return;
        }
        L[x]=inf;
        for(register int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].to;dfs(v);
            L[x]=min(L[x],L[v]/edge[i].val);
            M[x]+=edge[i].val*M[v];
        }
        L[x]=min(L[x],m/M[x]);    //排除可能因钱不够的影响。 
        for(register int i=L[x];i>=0;i--){     //枚举买几个此物品。 
            memset(f,-0x3f,sizeof(f));
            f[0]=0;
            for(register int u=head[x];u;u=edge[u].nxt){
                int v=edge[u].to;
                for(register int j=m;j>=0;j--){     //枚举一共的花费。 
                    int sum=-inf;
                    for(register int k=0;k<=j;k++){  //枚举以v为根的子树的花费。 
                        sum=max(sum,f[j-k]+dp[v][edge[u].val*i][k]);
                                 //其他物品的收益加上以v为根的子树的最大花费。 
                        f[j]=sum;
                    }
                }
            }
            for(register int j=0;j<=i;j++)  //枚举有几个用来合成。 
                for(register int k=0;k<=m;k++)   //枚举花费多少。 
                    dp[x][j][k]=max(dp[x][j][k],f[k]+war[x]*(i-j));
        }
    }
    
    int main(){
        scanf("%d%d",&n,&m);
        memset(dp,-0x3f,sizeof(dp));
        for(register int i=1;i<=n;i++){
            scanf("%d",&war[i]);
            char c;
            cin>>c;
    //      cout<<c<<endl;
            if(c=='B')
                scanf("%d%d",&M[i],&L[i]);
            else{
                int nn;
                scanf("%d",&nn);
                for(register int j=1;j<=nn;j++){
                    int a,b;
                    scanf("%d%d",&a,&b);
                    add(i,a,b);
                    used[a]=1;
                }
            }
        }
    //  for(register int i=1;i<=n;i++)  cout<<used[i]<<endl;
        for(register int i=1;i<=n;i++)
            if(!used[i]){
                dfs(i);
                for(register int j=m;j>=0;j--)    //枚举总共花了多少钱。 
                    for(register int k=0;k<=j;k++)    //枚举以i为根的子树的花费。 
                        ans[j]=max(ans[j],ans[j-k]+dp[i][0][k]);
            }
    //  for(register int i=1;i<=m;i++) cout<<ans[i]<<endl;
        printf("%d
    ",ans[m]);
        return 0;
    }
  • 相关阅读:
    SRM 582 Div II Level Three: ColorTheCells, Brute Force 算法
    SRM 583 Div II Level One:SwappingDigits
    SRM 583 Div Level Two:IDNumberVerification
    [置顶] gis海量资源网盘提供VIP账号无广告高速下载 (更新更多资源)
    为什么必须是final的呢?
    SRM 583 Div II Level Three:GameOnABoard,Dijkstra最短路径算法
    【学习opencv第七篇】图像的阈值化
    quartz 2.1学习(一)
    [置顶] C++之TinyXML的使用介绍
    写个小程序来比对两个目录下的不同文件
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9677094.html
Copyright © 2011-2022 走看看