题解:P4037 [JSOI2008] 魔兽地图

一道非常综合的背包题。

我们发现每一个点的选择对它的父亲的合成有影响。

这样的话我们可以尝试把这个因素记下来。

frt,i,j 来表示 rt 及它的子树中选择 i 个作为合成的材料的话,花费 j 的最大战斗力。

这样的话我们就可以直接用多重背包来写了。

先枚举 rt 的合成数量,在对每一个子树枚举,多重背包更新即可。

这里最好在转移的时候再加一个 g 数组,来记一下在此合成数量的花费为 i 时的最大收益。

每次清空一下即可。

可能有森林的情况,所以要把每一个点都枚举过来。

代码还是比较短的,重要在多重背包的写法,可以借鉴一下。

#include<bits/stdc++.h> #define pii pair<int,int> using namespace std; const int N=55,inf =1e9; int n,m,a[N],b[N],cnt[N],d[N],fa[N],f[55][105][2005],g[2005],ans; //表示f[u][i][j] u这个子树 i的花费,j用于合成的最大贡献 char c; void tomax(int &x,int y){if(x<y)x=y;} vector<pii>e[N]; void dfs(int rt) { for(auto p:e[rt]) { int u=p.first,c=p.second; dfs(u); cnt[rt]=min(cnt[rt],cnt[u]/c); b[rt]+=b[u]*c; } cnt[rt]=min(cnt[rt],m/b[rt]); for(int i=0; i<=cnt[rt]; i++){//至多能拥有多少 int now=i*b[rt]; memset(g,0,sizeof g); for(auto tmp:e[rt]) { int u=tmp.first,c=i*tmp.second;//需要的数量 for(int k=m; k>=0; k--) for(int o=0; o<=k; o++) tomax(g[k],g[k-o]+f[u][c][o]); } for(int j=0; j<=i; j++) for(int k=m; k>=now; k--) tomax(f[rt][j][k-j*b[rt]],g[k-now]+(i-j)*a[rt]),tomax(ans,f[rt][j][k]); } } int main() { scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { cin>>a[i]>>c; if(c=='A') { scanf("%d",&d[i]); cnt[i]=inf; for(int j=1,num,id; j<=d[i]; j++) { scanf("%d%d",&id,&num); e[i].push_back({id,num}); fa[id]=i; } } else scanf("%d%d",&b[i],&cnt[i]); } for(int i=1;i<=n;i++)if(!fa[i])dfs(i); cout<<ans; return 0; }

常数可能有点大,需要加快读才能过。


__EOF__

本文作者火牛
本文链接https://www.cnblogs.com/hnczy/p/18705992.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   hnczy  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示