[BZOJ1017][JSOI2008]魔兽地图DotR 树形dp

1017: [JSOI2008]魔兽地图DotR

Time Limit: 30 Sec  Memory Limit: 162 MB
Submit: 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

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

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 }
View Code

 

posted @ 2017-10-10 19:32  wls001  阅读(176)  评论(0编辑  收藏  举报