P4037 [JSOI2008] 魔兽地图 sol-树形dp+背包
20230921
P4037 [JSOI2008] 魔兽地图 sol
前言
历经千辛万苦终于调出来了,
细节不是有点多吧~
还参考了题解……
Statement
有
Solution
没有什么好的思路,
但很容易发现可以 dp。
我们用
注意
于是对于每一棵树,我们都从它的根出发,不断往下 dfs 用树形 dp 求解,
代码已经很清楚明白,
注意一定要从树的根走下去!!!
#include <bits/stdc++.h>
using namespace std;
const int N=55,M=2e3+5,inf=1e9;
int n,m,w[N],val[N],cnt[N],head[N],tot=0,g[M],ans[M],f[N][N<<1][M],vv[N];
struct edge{
int v,nxt,w;
}e[N<<2];
bool vis[N];
char ch[5];
void add(int u,int v,int y){
e[++tot]=(edge){v,head[u],y};
head[u]=tot;vv[v]++;//vv是用来记录它是否有贡献,保证从根开始枚举!!!
}
void dfs(int u){
if(vis[u]) return ;
vis[u]=true;
if(!head[u]){
cnt[u]=min(cnt[u],m/w[u]);
for(int i=cnt[u];i>=0;i--)
for(int j=i;j<=cnt[u];j++)
f[u][i][j*w[u]]=val[u]*(j-i);
return ;
}
cnt[u]=inf;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v;
dfs(v);
cnt[u]=min(cnt[u],cnt[v]/e[i].w);
w[u]+=e[i].w*w[v];
}
cnt[u]=min(cnt[u],m/w[u]);
for(int i=cnt[u];i>=0;i--){
memset(g,-0x3f,sizeof(g));g[0]=0;
for(int j=head[u];j;j=e[j].nxt){
int v=e[j].v;
for(int k=m;k>=0;k--){
int res=-inf;
for(int p=0;p<=k;p++)
res=max(res,g[k-p]+f[v][i*e[j].w][p]);
g[k]=res;
}
}
for(int j=0;j<=i;j++)
for(int k=0;k<=m;k++)
f[u][j][k]=max(f[u][j][k],g[k]+val[u]*(i-j));
}
}
int main(){
/*2023.9.21 H_W_Y P4037 [JSOI2008] 魔兽地图 树形背包*/
scanf("%d%d",&n,&m);
memset(f,-0x3f,sizeof(f));
for(int i=1,x;i<=n;i++){
scanf("%d",&val[i]);
scanf("%s",ch);
if(ch[0]=='A'){
scanf("%d",&x);
for(int j=1,v,y;j<=x;j++){
scanf("%d%d",&v,&y);
add(i,v,y);
}
}
else scanf("%d%d",&w[i],&cnt[i]);
}
for(int i=1;i<=n;i++)
if(!vv[i]){
dfs(i);
for(int j=m;j>=0;j--)
for(int k=0;k<=j;k++)
ans[j]=max(ans[j],ans[j-k]+f[i][0][k]);
}
printf("%d\n",ans[m]);
return 0;
}
Conclusion
树形 dp 与背包的结合,看着办吧~
一定要注意初始化和细节!
本文作者:H_W_Y
本文链接:https://www.cnblogs.com/H-W-Y/p/17719634.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
标签:
,
,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步