【來源】
【題目描述】
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。
表示以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;
}