bzoj 1017[JSOI2008]魔兽地图DotR - 树形dp

1017: [JSOI2008]魔兽地图DotR

Time Limit: 30 Sec  Memory Limit: 162 MB

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

 

好神的dp!

因为装备的合成路线是一棵树,所以我们可以套用树形dp.

我们设状态 f[i][j][k] 表示 到了第i个装备有j个用于向上合成一共花费k元能得到的最大力量

转移时我们枚举每个装备的购买数量L

g[i][j] 表示到第i个儿子花了j元的最大力量

g[i][j]可以用背包转移

f[i][j][k] = g[last son][k] + (L - j) * p[i];

然而复杂度很玄学,要加一个剪枝

v[i] 是装备合成的总价格, l[i] 表示i的最大上限

l[i] = min(l[son] / 合成所需, M / v[i]);

于是就过了。。。

 

 

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib> 
  5 #include <algorithm>
  6 #define LL long long
  7 
  8 using namespace std;
  9 
 10 const int MAXN = 100, MAXM = 3000;
 11 int N, M;
 12 int cnt = 0;
 13 int ans[MAXN][MAXM];
 14 int maxn;
 15 int head[MAXN];
 16 int p[MAXN];
 17 int v[MAXN];
 18 int l[MAXN];
 19 int in[MAXN];
 20 int f[MAXN][MAXN][MAXM];
 21 int gg[MAXN][MAXM];
 22 
 23 struct edge {
 24     int need;
 25     int v;
 26     int next;
 27 } g[MAXM * 2];
 28 char kind[100][10];
 29 
 30 void addedge(int u, int v, int w)
 31 {
 32     g[++cnt].v = v;
 33     g[cnt].next = head[u];
 34     g[cnt].need = w;
 35     head[u] = cnt;
 36 }
 37 inline LL read()
 38 {
 39     LL x = 0, w = 1; char ch = 0;
 40     while(ch < '0' || ch > '9') {
 41         if(ch == '-') {
 42             w = -1;
 43         }
 44         ch = getchar();
 45     }
 46     while(ch >= '0' && ch <= '9') {
 47         x = x * 10 + ch - '0';
 48         ch = getchar();
 49     }
 50     return x * w;
 51 }
 52 
 53 void DFS(int x)
 54 {
 55     if(kind[x][0] == 'A') {
 56         l[x] = MAXN;
 57         for(int j = head[x]; j; j = g[j].next) {
 58             int to = g[j].v;
 59             DFS(to);
 60             v[x] += v[to] * g[j].need;
 61             l[x] = min(l[x], l[to] / g[j].need);
 62         }
 63         l[x] = min(l[x], M / v[x]);
 64         for(int L = l[x]; L >= 0; L--) { // 枚举x装备购买数量 
 65             int tot = 0;
 66             memset(gg, -0x3f3f3f3f, sizeof gg);
 67                gg[0][0] = 0;
 68             for(int j = head[x]; j; j = g[j].next) {
 69                 ++tot;
 70                 int to = g[j].v;
 71                 for(int m = 0; m <= M; m++) {
 72                     for(int k = 0; k <= m; k++) {
 73                         gg[tot][m] = max(gg[tot][m], gg[tot - 1][k] + f[to][L * g[j].need][m - k]); 
 74                     }
 75                 }
 76             }
 77             for(int k = 0; k <= M; k++) {
 78                 for(int j = 0; j <= L; j++) {
 79                     f[x][j][k] = max(f[x][j][k], gg[tot][k] + (L - j) * p[x]);
 80                 }
 81             }
 82         }
 83     } else {
 84         for(int L = 0; L <= min(M / v[x], l[x]); L++) {
 85             for(int j = 0; j <= L; j++) {
 86                 f[x][j][v[x] * L] = (L - j) * p[x];
 87             }
 88         }
 89     }
 90 }
 91 int main()
 92 {
 93 //    freopen("t.out", "w", stdout);
 94     memset(f, -0x3f3f3f3f, sizeof f);
 95     N = read(), M = read();
 96     for(int i = 1; i <= N; i++) {
 97         p[i] = read();
 98         scanf("%s", kind[i]);
 99         if(kind[i][0] == 'A') {
100             int C = read();
101             for(int j = 1; j <= C; j++) {
102                 int v = read(), w = read();
103                 in[v]++;
104                 addedge(i, v, w);
105             }
106         } else {
107             v[i] = read(), l[i] = read();
108         }
109     }
110     int tot = 0;
111     for(int i = 1; i <= N; i++) {
112         if(!in[i]) {
113             ++tot;
114             DFS(i);
115             for(int j = 0; j <= M; j++) {
116                 for(int k = 0; k <= j; k++) {
117                     //for(int t = 0; t <= l[t]; t++) {
118                         ans[tot][j] = max(ans[tot][j], ans[tot - 1][k] + f[i][0][j - k]);
119                     //}
120                 }
121             }
122         }
123     }
124     for(int i = 0; i <= M; i++) {
125         maxn = max(ans[tot][i], maxn);
126     }
127     printf("%d\n", maxn);
128     return 0;
129 }
130 
131 /*
132 
133 10 59
134 5 A 3 6 1 9 2 10 1
135 1 B 5 3
136 1 B 4 3
137 1 B 2 3
138 8 A 3 2 1 3 1 7 1
139 1 B 5 3
140 5 B 3 3
141 15 A 3 1 1 5 1 4 1
142 1 B 3 5
143 1 B 4 3
144 
145 */
View Code

 

posted @ 2018-02-10 10:22  大财主  阅读(268)  评论(0编辑  收藏  举报