bzoj 1017 魔兽地图DotR

题目大意:

他们需要购买装备来提升自己的力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力量值之和。装备分为基本装备和高级装备两种。基本装备可以直接从商店里面用金币购买,而高级装备需要用基本装备或者较低级的高级装备来合成,合成不需要附加的金币。装备的合成路线可以用一棵树来表示。比如,Sange and Yasha的合成需要Sange,Yasha和Sange and Yasha Recipe Scroll三样物品。其中Sange又要用Ogre Axe, Belt of Giant Strength和 Sange Recipe Scroll合成。每件基本装备都有数量限制,这限制了你不能无限制地合成某些性价比很高的装备。现在,英雄Spectre有M个金币,他想用这些钱购买装备使自己的力量值尽量高。

已知每个高级装备需要哪些初级下一级装备以及需要几个

思路:

树形dp

dp i  j k表示第i种装备,有j个用于合成上一级装备,花k个金币

首先可以得到整个图应该是很多树

然后对于每个节点,我们都可以根据它的子树推出来

f[i][j][k]=max{c[i][k]+v[i]*(t-j)}

然后我们枚举这个节点有多少个需要用于合成(需要倒序枚举 不然爆炸)

最后对于每棵树

我们可以枚举钱数,来求出这棵树买多少

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<map>
11 #include<stack>
12 #define inf 2147483611
13 #define ll long long
14 #define MAXN 55
15 using namespace std;
16 inline int read()
17 {
18     int x=0,f=1;
19     char ch=getchar();
20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
22     return x*f;
23 }
24 int n,m,v[MAXN],cst[MAXN],lim[MAXN];
25 int cnt,to[MAXN*MAXN*10],val[MAXN*MAXN*10],first[MAXN],next[10*MAXN*MAXN],ind[MAXN];//邻接表 
26 int f[MAXN][MAXN*2][MAXN*40],c[MAXN][MAXN*40],res[MAXN][MAXN*40];
27 //f为dp数组 c记录某节点前x个子树花j个金币所获得最大收益 res记录前k棵树花j个金币获得最大收益 
28 void add(int u,int v,int d) {next[++cnt]=first[u],first[u]=cnt,val[cnt]=d,to[cnt]=v,ind[v]++;}
29 void dp(int x)
30 {
31     if(!first[x])
32     {
33         lim[x]=min(lim[x],m/cst[x]);
34         for(int i=0;i<=lim[x];i++)
35             for(int j=i;j<=lim[x];j++)
36                 f[x][i][j*cst[x]]=v[x]*(j-i);
37         return ;
38     }
39     lim[x]=inf;
40     for(int i=first[x];i;i=next[i])
41     {
42         dp(to[i]);
43         lim[x]=min(lim[x],lim[to[i]]/val[i]);
44         cst[x]+=val[i]*cst[to[i]];
45     }
46     lim[x]=min(lim[x],m/cst[x]);
47     memset(c,-0x3f3f3f3f,sizeof(c));
48     c[0][0]=0;
49     int cntt;
50     for(int t=lim[x];t>=0;t--)
51     {
52         cntt=0;
53         for(int i=first[x];i;i=next[i])
54         {
55             cntt++;
56             for(int j=0;j<=m;j++)
57                 for(int k=0;k<=j;k++)
58                     c[cntt][j]=max(c[cntt][j],c[cntt-1][j-k]+f[to[i]][t*val[i]][k]);
59         }
60         for(int i=0;i<=t;i++)
61             for(int j=0;j<=m;j++)
62                 f[x][i][j]=max(f[x][i][j],c[cntt][j]+(t-i)*v[x]);
63     }
64 }
65 int main()
66 {
67     memset(f,-0x3f3f3f3f,sizeof(f));
68     n=read(),m=read();
69     char ch[3];int x,b,a,ans=0;
70     for(int i=1;i<=n;i++)
71     {
72         v[i]=read();
73         scanf("%s",ch);
74         if(ch[0]=='A') 
75         {
76             x=read();
77             for(int j=1;j<=x;j++) {a=read(),b=read();add(i,a,b);}
78         }
79         else cst[i]=read(),lim[i]=read();
80     }
81     cnt=0;
82     for(int g=1;g<=n;g++)
83     {
84         if(!ind[g])
85         {
86             dp(g);
87             cnt++;
88             for(int i=0;i<=m;i++)
89                 for(int j=0;j<=i;j++)
90                     for(int k=0;k<=lim[g];k++)
91                         res[cnt][i]=max(res[cnt][i],res[cnt-1][j]+f[g][k][i-j]);
92         }
93     }
94     for(int i=0;i<=m;i++) ans=max(ans,res[cnt][i]);
95     printf("%d",ans);
96 }
View Code

orz vfk大佬速度惊人,博客太长了懒得看

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7652910.html