1017: [JSOI2008]魔兽地图DotR
Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1230 Solved: 522
[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
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
HINT
Source
题意:玩过游戏的都懂,给出一棵树,每个节点都可以由下面的节点按一定数量合成,每个节点可以提供一定力量,孩子节点有数量限制,问用一定金钱,能得到的最大力量
分析:题目很明确,一棵树,一棵树上的Dp,树形DP
状态很容易想Dp[i][j][k] 表示第 i 个点,恰好花去k元其中 必须合成 j 个提供给父亲节点合成用,所能得到的最大力量(不包括提供给父亲的那部分)
转移时维护一个辅助数组F[x][i][j]
表示第 x 个节点,前 i 个孩子, 花去 j 元能获得的最大力量,具体看代码吧,要在枚举提供给父亲节点的数目的前提下计算(废话)
综上所述,本题得解
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <deque> 6 #include <vector> 7 #include <queue> 8 #include <iostream> 9 #include <algorithm> 10 #include <map> 11 #include <set> 12 #include <ctime> 13 using namespace std; 14 typedef long long LL; 15 #define For(i, s, t) for(int i = (s); i <= (t); i++) 16 #define Ford(i, s, t) for(int i = (s); i >= (t); i--) 17 #define MIT (2147483647) 18 #define INF (1000000001) 19 #define MLL (1000000000000000001LL) 20 #define sz(x) ((bnt) (x).size()) 21 #define clr(x, y) memset(x, y, sizeof(x)) 22 #define puf push_front 23 #define pub push_back 24 #define pof pop_front 25 #define pob pop_back 26 #define ft first 27 #define sd second 28 #define mk make_pair 29 inline void SetIO(string Name) { 30 string Input = Name+".in", 31 Output = Name+".out"; 32 freopen(Input.c_str(), "r", stdin), 33 freopen(Output.c_str(), "w", stdout); 34 } 35 36 const int N = 60, M = 2010, Max = 110; 37 int n, m; 38 int Root, Dp[N][Max][M], F[N][N][M]; 39 int Fa[N], Need[N][N], Child[N][N], LC[N]; 40 int Power[N], Money[N], Limit[N]; 41 bool Visit[N], Basic[N]; 42 43 inline void Input() { 44 scanf("%d%d", &n, &m); 45 For(i, 1, n) { 46 scanf("%d", &Power[i]); 47 char ch = ' '; 48 while(ch != 'A' && ch != 'B') ch = getchar(); 49 if(ch == 'A') { 50 scanf("%d", &LC[i]); 51 For(j, 1, LC[i]) { 52 scanf("%d%d", &Child[i][j], &Need[i][j]); 53 Visit[Child[i][j]] = 1; 54 } 55 } else { 56 scanf("%d%d", &Money[i], &Limit[i]); 57 Limit[i] = min(Limit[i], m/Money[i]), Basic[i] = 1; 58 } 59 } 60 } 61 62 inline void CalnLimit(int x) { 63 if(Basic[x]) return; 64 Limit[x] = INF, Money[x] = 0; 65 For(i, 1, LC[x]) { 66 int y = Child[x][i]; 67 CalnLimit(y); 68 Limit[x] = min(Limit[x], Limit[y]/Need[x][i]); 69 Money[x] += Money[y]*Need[x][i]; 70 } 71 Limit[x] = min(Limit[x], m/Money[x]); 72 } 73 74 inline void Search(int x) { 75 if(Basic[x]) { 76 For(i, 0, Limit[x]) 77 For(j, i, Limit[x]) 78 Dp[x][i][j*Money[x]] = (j-i)*Power[x]; 79 } else { 80 For(i, 1, LC[x]) Search(Child[x][i]); 81 82 For(k, 0, Limit[x]) { 83 For(i, 0, LC[x]) 84 For(j, 0, m) F[x][i][j] = -INF; 85 F[x][0][0] = 0; 86 87 For(i, 1, LC[x]) 88 For(j, 0, m) 89 For(g, 0, j) 90 F[x][i][j] = max(F[x][i][j], 91 F[x][i-1][j-g]+Dp[Child[x][i]][k*Need[x][i]][g]); 92 93 For(i, 0, k) 94 For(g, 0, m) 95 Dp[x][i][g] = max(Dp[x][i][g], F[x][LC[x]][g]+Power[x]*(k-i)); 96 } 97 } 98 } 99 100 inline void Solve() { 101 For(i, 1, n) 102 if(!Visit[i]) { 103 Root = i; 104 break; 105 } 106 107 CalnLimit(Root); 108 109 For(i, 1, n) 110 For(j, 0, Limit[i]) 111 For(k, 0, m) Dp[i][j][k] = -INF; 112 Search(Root); 113 114 int Ans = 0; 115 For(i, 0, m) Ans = max(Ans, Dp[Root][0][i]); 116 printf("%d\n", Ans); 117 } 118 119 int main() { 120 SetIO("1017"); 121 Input(); 122 Solve(); 123 return 0; 124 }