[BZOJ1017][JSOI2008]魔兽地图DotR 树形dp
1017: [JSOI2008]魔兽地图DotR
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2597 Solved: 1010
[Submit][Status][Discuss]
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(幽灵附体)作为回报的。
Input
第一行包含两个整数,N (1 <= n <= 51) 和 m (0 <= m <= 2,000)。分别表示装备的种类数和金币数。装备
用1到N的整数编号。接下来的N行,按照装备1到装备n的顺序,每行描述一种装备。每一行的第一个非负整数表示这
个装备贡献的力量值。接下来的非空字符表示这种装备是基本装备还是高级装备,A表示高级装备,B表示基本装备
。如果是基本装备,紧接着的两个正整数分别表示它的单价(单位为金币)和数量限制(不超过100)。如果是高
级装备,后面紧跟着一个正整数C,表示这个高级装备需要C种低级装备。后面的2C个数,依次描述某个低级装备的
种类和需要的个数。
Output
第一行包含一个整数S,表示最多可以提升多少点力量值。
Sample Input
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
Sample Output
33
对于这道题,我们设f[i][j][k]表示处理到第i个点,向父亲节点合并j个装备,花了k元钱的最大力量值(不包括合并的j个)。
设g[i][j]表示当前节点的前i个子树花了j元钱的最大力量(不包括合并的)。
我们先枚举购买当前装备的总数量b,
对于f的转移,我们枚举j,k,有转移方程f[i][j][k]=max{g[i][k]+p[i]*(b-j)}
对于g的转移,我们枚举子树tot,钱数j和当前子树的钱数k,有g[tot][j]=max{g[tot-1][j-k]+f[i][b*e[i].v][k]}
之后统计答案即可
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 int read() { 9 int x=0,f=1;char ch=getchar(); 10 while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();} 11 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 int n,m,cnt,tot,ans; 15 int p[55],L[55],M[55]; 16 int f[55][105][2005]; 17 int g[55][2005],h[55][2005]; 18 char ch[5]; 19 int head[55],deg[55]; 20 struct data{int to,next,v;}e[20005]; 21 void add(int u,int v,int w){e[cnt].to=v;e[cnt].next=head[u];head[u]=cnt;e[cnt].v=w;cnt++;deg[v]++;} 22 void dfs(int now) { 23 if(head[now]<0) { 24 L[now]=min(L[now],m/M[now]); 25 for(int i=0;i<=L[now];i++) 26 for(int j=i;j<=L[now];j++) f[now][i][j*M[now]]=(j-i)*p[now]; 27 return ; 28 } 29 L[now]=214748364; 30 for(int i=head[now];i>=0;i=e[i].next) { 31 int to=e[i].to; 32 dfs(to); 33 L[now]=min(L[now],L[to]/e[i].v); 34 M[now]+=e[i].v*M[to]; 35 } 36 L[now]=min(L[now],m/M[now]); 37 memset(g,-47,sizeof(g)); 38 g[0][0]=0; 39 for(int b=L[now];b>=0;b--) { 40 int tot=0; 41 for(int i=head[now];i>=0;i=e[i].next) { 42 tot++; 43 for(int j=0;j<=m;j++) 44 for(int k=0;k<=j;k++){ 45 g[tot][j]=max(g[tot][j],g[tot-1][j-k]+f[e[i].to][b*e[i].v][k]);} 46 } 47 for(int i=0;i<=b;i++) 48 for(int j=0;j<=m;j++) 49 f[now][i][j]=max(f[now][i][j],g[tot][j]+p[now]*(b-i)); 50 } 51 } 52 int main() { 53 memset(head,-1,sizeof(head)); 54 memset(f,-47,sizeof(f)); 55 n=read(),m=read(); 56 for(int i=1;i<=n;i++) { 57 p[i]=read(); 58 scanf("%s",ch); 59 if(ch[0]=='A') { 60 int x=read(); 61 while(x--) { 62 int v=read(),num=read(); 63 add(i,v,num); 64 } 65 } 66 else M[i]=read(),L[i]=read(); 67 } 68 int sum=0; 69 for(int x=1;x<=n;x++) { 70 if(!deg[x]) { 71 dfs(x); 72 sum++; 73 for(int i=0;i<=m;i++) 74 for(int j=0;j<=i;j++) 75 for(int k=0;k<=L[x];k++) 76 h[sum][i]=max(h[sum][i],h[sum-1][j]+f[x][k][i-j]); 77 } 78 } 79 int ans=0; 80 for(int i=0;i<=m;i++) ans=max(ans,h[sum][i]); 81 cout<<ans; 82 }