【C++】「JSOI-2008」魔兽地图DotR

【来源】

BZOJ-1017
计蒜客-T2793
vjudge

【题目描述】

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,表示最多可以提升多少点力量值。

【样例输出】

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

【样例输出】

33

【解析】

树形dp。
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示以i为根的子树刚好花了k元,把j个贡献给父亲,此时的最大值,可以先计算全部贡献给父亲,然后计算部分贡献给父亲,注意用lim数组限制每次的枚举量,即某个点最多可以有几个。
另外,这题还有一个特殊情况,就是所有的点都没有父亲的情况,此时要做一个多重背包.

【代码】

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

#define RI                 register int
#define re(i,a,b)          for(RI i=a; i<=b; i++)
#define ms(i,a)            memset(a,i,sizeof(a))
#define MAX(a,b)           (((a)>(b)) ? (a):(b))
#define MIN(a,b)           (((a)<(b)) ? (a):(b))

using namespace std;

typedef long long LL;

namespace IO {
    
    
    #include <cctype>

    template <typename T>
    inline void read(T &x){
    
    
        x=0; 
        char c=0; 
        T w=0;  
        while (!isdigit(c)) w|=c=='-',c=getchar();  
        while (isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();  
        if(w) x=-x;  
    }
    
    template <typename T>
    inline void write(T x) {
    
    
        if(x<0) putchar('-'),x=-x;
        if(x<10) putchar(x+'0');
            else write(x/10),putchar(x%10+'0');
    }

    template <typename T>
    inline void writesp(T x) {
    
    
        write(x);
        putchar(' ');
    }
    
    template <typename T>
    inline void writeln(T x) {
    
    
        write(x);
        putchar('\n');
    }
} 

using IO::read;
using IO::write;
using IO::writesp;
using IO::writeln;

const int N=55;
const int M=2005;
const int inf=1e9;

struct Edge {
    
    
    int to,nt;
} e[M<<3];

int n,m,ans,cnt;
int v[N],lim[N],g[M],need[N],cost[N],h[N],fa[N];
int dp[N][M];
int f[N][105][M];

inline void add(int a,int b) {
    
    
    e[++cnt]=(Edge){
    
    b,h[a]};
    h[a]=cnt;
}

void dfs(int k) {
    
    
    if(!h[k]) {
    
    
        lim[k]=MIN(lim[k],m/cost[k]);
        for(int i=0; i<=lim[k]; i++) for(int j=0; j<=i; j++) 
            f[k][j][i*cost[k]]=(i-j)*v[k];
        return;
    }
    for(int i=h[k]; i; i=e[i].nt) {
    
    
        dfs(e[i].to);
        lim[k]=MIN(lim[k],lim[e[i].to]/need[e[i].to]);
    }
    for(int i=0; i<=lim[k]; i++) f[k][i][0]=0;
    for(int i=h[k]; i; i=e[i].nt) {
    
    
        for(int j=0; j<=lim[k]; j++) {
    
    
            memcpy(g,f[k][j],sizeof(f[k][j]));
            memset(f[k][j],-1,sizeof(f[k][j]));
            for(int x=m; x>=0; x--) for(int r=x; r>=0; r--) 
                if(g[x-r]!=-1 && f[e[i].to][j*need[e[i].to]][r]!=-1) {
    
    
                    f[k][j][x]=MAX(f[k][j][x],g[x-r]+f[e[i].to][j*need[e[i].to]][r]);
                    ans=MAX(f[k][j][x],ans);
                }
        }
    }
    for(int i=0; i<=lim[k]; i++) for(int j=i; j<=lim[k]; j++) 
        for(int x=0; x<=m; x++) if(f[k][j][x]!=-1) {
    
    
            f[k][i][x]=MAX(f[k][i][x],f[k][j][x]+(j-i)*v[k]);
            ans=MAX(ans,f[k][i][x]);
        }
}

int main() {
    
    
    read(n),read(m);
    for(int i=1; i<=n; i++) lim[i]=inf;
    for(int i=1; i<=n; i++) {
    
    
        read(v[i]);
        char s[2];
        scanf("%s",s);
        if(s[0]=='B') read(cost[i]),read(lim[i]);
            else {
    
    
                int k;
                read(k);
                while(k--) {
    
    
                    int x,y;
                    read(x),read(y);
                    fa[x]=1;
                    add(i,x);
                    need[x]=y;
                }
            }
    }
    int check=0;
    memset(f,-1,sizeof(f));
    for(int i=1; i<=n; i++) 
        if(!fa[i]) dfs(i);
            else check=1;
    if(!check) {
    
    
        for(int i=1; i<=n; i++) for(int j=0; j<=m; j++) 
            for(int k=0; k<=100; k++) {
    
    
                if(cost[i]*k>j || k>lim[i]) continue;
                dp[i][j]=MAX(dp[i][j],dp[i-1][j-cost[i]*k]+v[i]*k);
            }
        ans=dp[n][m];
    }
    writeln(ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ljnoit/article/details/105915895