【C++】「JSOI-2008」魔獸地圖DotR

【來源】

BZOJ-1017
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]表示以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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章