题意:
经典的 树 上 背 包 !!!
对于每一级物品,他肯定由部分更低级的物品合成,且部分这一级的物品将会用于合成更高级的物品。即每一层受到更低一层的影响,同时影响上一层。
我们用
l[u]=min(l[u],m/val[u]);
for(int i=l[u];i>=0;i--)
for(int j=i;j<=l[u];j++)
{
if(j*val[u]>m)
break;
d[u][i][j*val[u]]=p[u]*(j-i);
}
return ;
对于高级物品,我们先计算出它们的数量限制和价格。数量限制和价格都由低级物品的价格和所需数量决定。
l[u]=INF;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dfs(v);
l[u]=min(l[u],l[v]/e[i].num);
val[u]+=val[v]*e[i].num;
}
l[u]=min(l[u],m/val[u]);
接着考虑转移
for(int i=l[u];i>=0;i--)
{
memset(g,-0x3f,sizeof(g));
g[0]=0;
for(int j=head[u];j;j=e[j].next)
{
int v=e[j].to;
for(int k=m;k>=0;k--)
{
int o=-INF;
for(int l=0;l<=k;l++)
o=max(o,g[k-l]+d[v][i*e[j].num][l]);
g[k]=o;
}
}//第一部分
for(int j=0;j<=i;j++)
for(int k=0;k<=m;k++)
d[u][j][k]=max(d[u][j][k],g[k]+p[u]*(i-j));//第二部分
}
对于第一部分,
对于第二部分,
由于两个转移的决策之间互相影响,所以要另开数组
最后由于根节点代表顶级装备,可能有很多顶级装备,即森林,其中每棵树的贡献为
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#define INF 1e9
using namespace std;
const int maxn=2010;
const double Pi=acos(-1.0);
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,m,indgr[55],p[55],l[55],val[55];
int head[maxn<<1],cnt,vis[55],a[maxn],g[maxn];
int d[55][105][maxn],f[maxn];//d[i][j][k]表示第i个装备,用j个合成新装备,k个金币作为预算的最大贡献值。
struct node
{
int next;
int to;
int num;
}e[maxn<<1];
void add(int from,int to,int num)
{
e[++cnt].next=head[from];
e[cnt].to=to;
e[cnt].num=num;
head[from]=cnt;
}
void dfs(int u)
{
if(vis[u])
return ;
vis[u]=1;
if(!a[u])
{
l[u]=min(l[u],m/val[u]);
for(int i=l[u];i>=0;i--)
for(int j=i;j<=l[u];j++)
{
if(j*val[u]>m)
break;
d[u][i][j*val[u]]=p[u]*(j-i);
}
return ;
}
l[u]=INF;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
dfs(v);
l[u]=min(l[u],l[v]/e[i].num);
val[u]+=val[v]*e[i].num;
}
l[u]=min(l[u],m/val[u]);
for(int i=l[u];i>=0;i--)
{
memset(g,-0x3f,sizeof(g));
g[0]=0;
for(int j=head[u];j;j=e[j].next)
{
int v=e[j].to;
for(int k=m;k>=0;k--)
{
int o=-INF;
for(int l=0;l<=k;l++)
o=max(o,g[k-l]+d[v][i*e[j].num][l]);
g[k]=o;
}
}
for(int j=0;j<=i;j++)
for(int k=0;k<=m;k++)
d[u][j][k]=max(d[u][j][k],g[k]+p[u]*(i-j));
}
}
int main()
{
memset(l,0x3f,sizeof(l));
memset(d,-0x3f,sizeof(d));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
char c;
scanf(" %c",&c);
if(c=='A')
{
a[i]=1;
int q;
scanf("%d",&q);
for(int j=1;j<=q;j++)
{
int x,y;
scanf("%d%d",&x,&y);
add(i,x,y);
indgr[x]++;
}
}
else
scanf("%d%d",&val[i],&l[i]);
}
for(int i=1;i<=n;i++)
if(!indgr[i])//根节点
{
dfs(i);
for(int j=m;j>=0;j--)
for(int k=0;k<=j;k++)
f[j]=max(f[j],f[j-k]+d[i][0][k]);
}
printf("%d",f[m]);
return 0;
}