[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

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

分析

     TAT这是我写过的最麻烦的一道树形依赖背包!(虽然这也是我第一次写= =)

     不过说实话,这题的“思路”还是相当简单的……大概就是先dfs一下整棵进化树,得到每个节点的以下信息:这棵子树上最多的花费(maxcost),根节点最多能买到几个(maxcnt)(可以由它依赖的节点的maxcnt和需要依赖节点的个数求得),买一个此装备的价格,和这个装备产生的力量值。对于每个节点,设f(i,j)表示提供给父节点i个当前节点用于合成,且在这棵子树上恰好花费j金币时可得的最大力量值(父节点的力量值不算),然后每个节点与它的右兄弟和左儿子分别合并答案即可。

     具体的合并算法还是参考了巨神VFleaKing的题解……

 

  1 /*====================Asm.Def========================*/
  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 }
树形依赖背包

 

posted @ 2015-03-27 18:21  Asm.Definer  阅读(219)  评论(0编辑  收藏  举报