zoukankan      html  css  js  c++  java
  • [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 ", 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 }
    树形依赖背包
  • 相关阅读:
    验证LeetCode Surrounded Regions 包围区域的DFS方法
    Qt Package Project 打包发布程序
    [LeetCode] Missing Number 丢失的数字
    [CareerCup] 6.4 Blue Eyes People on Island 岛上的蓝眼人
    [CareerCup] 6.3 Water Jug 水罐问题
    [CareerCup] 6.2 Dominos on Chess Board 棋盘上的多米诺
    [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子
    [CareerCup] 5.8 Draw Horizonatal Line 画横线
    Print or Cout an Unsigned Char Variable 打印无符号字符
    Kinect 学习链接
  • 原文地址:https://www.cnblogs.com/Asm-Definer/p/4372581.html
Copyright © 2011-2022 走看看