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 }
orz vfk大佬速度惊人,博客太长了懒得看