[bzoj1017][JSOI2008]魔兽地图 DotR (Tree DP)【有待优化】
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
分析
TAT这是我写过的最麻烦的一道树形依赖背包!(虽然这也是我第一次写= =)
不过说实话,这题的“思路”还是相当简单的……大概就是先dfs一下整棵进化树,得到每个节点的以下信息:这棵子树上最多的花费(maxcost),根节点最多能买到几个(maxcnt)(可以由它依赖的节点的maxcnt和需要依赖节点的个数求得),买一个此装备的价格,和这个装备产生的力量值。对于每个节点,设f(i,j)表示提供给父节点i个当前节点用于合成,且在这棵子树上恰好花费j金币时可得的最大力量值(父节点的力量值不算),然后每个节点与它的右兄弟和左儿子分别合并答案即可。
具体的合并算法还是参考了巨神VFleaKing的题解……
2 #include <iostream>
3 #include <cctype>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <algorithm>
7 #include <ctime>
8 #include <queue>
9 using namespace std;
10 inline void getd(int &x){
11 char c = getchar();
12 bool minus = 0;
13 while(!isdigit(c) && c != ‘-‘)c = getchar();
14 if(c == ‘-‘)minus = 1, c = getchar();
15 x = c - ‘0‘;
16 while(isdigit(c = getchar()))x = x * 10 + c - ‘0‘;
17 if(minus)x = -x;
18 }
19 /*======================================================*/
20 const int maxn = 53, maxm = 2003, maxc = 102, INF = 0x7fffffff;
21 typedef long long LL;
22 struct Node{
23 Node *son, *bro;
24 int maxcost, maxcnt, cnt, pri, val;
25 int f[maxc][maxm], S[maxc][maxm];
26 void dfs();
27 void dp();
28 }node[maxn], *Root;
29 int N, M, tmp[maxm];
30
31 void Node::dfs(){
32 if(son == NULL){
33 maxcnt = min(M / pri, maxcnt);
34 if((LL)maxcnt * pri > M)maxcnt = 0, maxcost = 0;
35 else maxcost = maxcnt * pri;
36 return;
37 }
38 Node *it = son;
39 maxcnt = INF;
40 while(it != NULL){
41 it->dfs();
42 maxcost = min(M, maxcost + it->maxcost);
43 if((LL)it->pri * it->cnt > M)
44 pri = 0, maxcnt = 0;
45 else{
46 pri += it->pri * it->cnt;
47 maxcnt = min(maxcnt, it->maxcnt / it->cnt);
48 }
49 it = it->bro;
50 }
51 if(pri)maxcnt = min(M / pri, maxcnt);
52 else maxcnt = 0;
53 }
54
55 inline void init(){
56 getd(N), getd(M);
57 unsigned long long NotRoot = 1;
58 int i, j, k, ch;
59 for(i = 1;i <= N;++i){
60 getd(node[i].val);
61 while(!isalpha(ch = getchar()));
62 if(ch == ‘A‘){
63 getd(j);getd(k);
64 getd(node[k].cnt);
65 node[i].son = node + k;
66 NotRoot |= (1ll << k);
67 while(--j){
68 getd(k);getd(node[k].cnt);
69 node[k].bro = node[i].son;
70 node[i].son = node + k;
71 NotRoot |= (1ll << k);
72 }
73 }
74 else
75 getd(node[i].pri), getd(node[i].maxcnt);
76 }
77 NotRoot = (~NotRoot) & (NotRoot + 1);
78 i = 0;
79 while(NotRoot > 1)++i, NotRoot >>= 1;
80 Root = node + i;
81 Root->dfs();
82 }
83
84 inline void AddTo(int *S, int *f, int limS, int limf){
85 int i, j;
86 for(i = 1;i <= limS;++i){
87 tmp[i] = 0;
88 for(j = 0;j <= min(limf, i);++j)if(f[j] + S[i-j] > tmp[i])
89 tmp[i] = f[j] + S[i-j];
90 }
91 for(i = 1;i <= limS;++i)S[i] = tmp[i];
92 }
93
94 void Node::dp(){
95 int i, j;
96 Node *it;
97 if(son != NULL)for(it = son;it != NULL;it = it->bro){
98 it->dp();
99 for(i = 0;i <= maxcnt;++i)
100 AddTo(S[i], it->f[i*it->cnt], maxcost, it->maxcost);
101 for(j = 1;j <= maxcost;++j)
102 f[maxcnt][j] = max(S[maxcnt][j], f[maxcnt][j-1]);
103 }
104 for(i = maxcnt-1;i >= 0;--i)for(j = 1;j <= maxcost;++j){
105 f[i][j] = max(f[i][j-1], S[i][j]);
106 if(j >= pri && f[i+1][j-pri] + val > f[i][j])
107 f[i][j] = f[i+1][j-pri] + val;
108 }
109 }
110
111 int main(){
112 #if defined DEBUG
113 freopen("test", "r", stdin);
114 #else
115 freopen("bzoj_1017.in", "r", stdin);
116 freopen("bzoj_1017.out", "w", stdout);
117 #endif
118 init();
119
120 Root->dp();
121 printf("%d\n", Root->f[0][Root->maxcost]);
122
123 #if defined DEBUG
124 cout << endl << (double)clock()/CLOCKS_PER_SEC << endl;
125 #endif
126 return 0;
127 }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。