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
HINT
Source
很明显的树形dp。开始我不会d,所以准备照着hzwer的copy,后来弄懂了树p的真谛,天黑都不怕了。
树p一般都要开dp两次,通过第一个dp结果来dp第二个,再根据第二个来更新第一个(等于第二个dp只是个桥梁吧)。
像这一题,f[i][j][k]表示i物品贡献给父亲j个花了k的最大力量,通过g数组来完成转移。g[i][k]表示考虑前i个儿子,花j的最大费用,单其实只要一维就够了,因为它可以滚动使用。
如果实在是听不的话,看代码就行了。我就是看代码才理解的。
1 #include<iostream> 2 #include<cstring> 3 #include<vector> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cstdlib> 7 using namespace std; 8 9 #define inf (1<<29) 10 #define maxn 60 11 #define maxm 2010 12 #define maxl 110 13 int n,m,con[maxn],pri[maxn],lim[maxn]; 14 int f[maxn][maxl][maxm],g[maxm],root,ans; 15 bool bas[maxn]; 16 vector < pair <int,int> > need[maxn]; 17 18 inline int Max(int a,int b) { if (a > b) return a; return b; } 19 20 inline int Min(int a,int b) { if (a < b) return a; return b; } 21 22 inline int getint() 23 { 24 int x=0,f=1;char ch=getchar(); 25 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} 26 while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} 27 return x*f; 28 } 29 30 inline void read() 31 { 32 for (int i = 1;i <= n;++i) 33 { 34 con[i] = getint(); 35 char opt = getchar(); 36 if (opt == ‘A‘) 37 { 38 int nn = getint(); 39 for (int j = 1;j <= nn;++j) 40 { 41 int a = getint(),b = getint(); 42 need[i].push_back(make_pair(a,b)); 43 bas[a] = true; 44 } 45 lim[i] = inf; 46 } 47 else pri[i] = getint(),lim[i] = getint(); 48 } 49 for (int i = 1;i <= n;++i) 50 if (!bas[i]) { root = i; break; } 51 } 52 53 inline void dp(int now) 54 { 55 if (need[now].size() == 0) 56 { 57 lim[now] = Min(lim[now],m/pri[now]); 58 for (int i = 0;i <= lim[now];++i) 59 for (int j = i;j <= lim[now];++j) 60 f[now][i][j*pri[now]] = (j-i)*con[now]; 61 return; 62 } 63 lim[now] = inf; int nn = need[now].size(); 64 for (int i = 0;i < nn;++i) 65 dp(need[now][i].first),lim[now] = Min(lim[now],lim[need[now][i].first]/need[now][i].second); 66 for (int i = 0;i <= lim[now];++i) f[now][i][0] = 0; 67 for (int i = 0;i < nn;++i) 68 for (int j = 0;j <= lim[now];++j) 69 { 70 memcpy(g,f[now][j],sizeof(g)); 71 memset(f[now][j],-1,sizeof(g)); 72 for (int k = m;k >= 0;--k) 73 { 74 for (int r = k;r >= 0; --r) 75 if (g[k - r] != -1&&f[need[now][i].first][j*need[now][i].second][r] != -1) 76 { 77 f[now][j][k] = Max(f[now][j][k],g[k-r]+f[need[now][i].first][j*need[now][i].second][r]); 78 ans = Max(ans,f[now][j][k]); 79 } 80 } 81 } 82 for (int i = 0;i <= lim[now];++i) 83 for (int j = i;j <= lim[now];++j) 84 for (int k = 0;k <= m;++k) 85 { 86 if (f[now][j][k] == -1) continue; 87 f[now][i][k] = Max(f[now][i][k],f[now][j][k] + (j-i)*con[now]),ans = Max(ans,f[now][i][k]); 88 } 89 } 90 91 int main() 92 { 93 freopen("1017.in","r",stdin); 94 freopen("1017.out","w",stdout); 95 memset(f,-1,sizeof(f)); 96 scanf("%d %d",&n,&m); 97 read(); 98 dp(root); 99 printf("%d",ans); 100 fclose(stdin); fclose(stdout); 101 return 0; 102 }