P4037 [JSOI2008] 魔兽地图 题解
提供一种新思路
现有的大部分题解记
我的状态记
在操作上会复杂一些,但是感觉上可能更加直观。
先处理出
易得
同时可以注意到,给出的图可能是森林,那么要为再为散开的树设计一个背包综合答案。
code:
#include<bits/stdc++.h>
using namespace std;
inline void rd(int &x){
int s=0,f=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=0; c=getchar();}
while(c>='0'&&c<='9'){s=s*10+c-48; c=getchar();}
x=f? s:-s;
}
const int N=55,M=2e3+5,inf=1e9;
struct edge{int to,w,nt;} e[M]; int hd[N],ect;
void ade(int u,int v,int w){e[++ect]={v,w,hd[u]}; hd[u]=ect;}
int n,m,in[N],val[N],Lim[N],Cost[N];
int f[N][105][M],g[M];
//f[u][i][j] u装备生产至少 i个,总花费为 j,最大力量值
//g[]为树上背包时的辅助转移的临时数组
void cklp(int F[][M],int u){
for(int i=Lim[u]-1; ~i; i--){
for(int j=0; j<=m; j++){
F[i][j]=max(F[i][j], F[i+1][j]);
}
}
}
void dfs(int u){
memset(f[u],~63,sizeof(f[u]));
if(!hd[u]){
Lim[u]=min(Lim[u],m/Cost[u]);
for(int i=0; i<=Lim[u]; i++)
f[u][i][i*Cost[u]]=i*val[u];
cklp(f[u], u);
return;
}
Lim[u]=inf;
for(int i=hd[u]; i; i=e[i].nt){
int v=e[i].to, w=e[i].w;
dfs(v);
Lim[u]=min(Lim[u], Lim[v]/w);
Cost[u]+=Cost[v]*w;
}
Lim[u]=min(Lim[u],m/Cost[u]);
for(int i=0; i<=Lim[u]; i++){
memset(g,~63,sizeof(g)); g[0]=0;
for(int Ei=hd[u]; Ei; Ei=e[Ei].nt){
int v=e[Ei].to, w=e[Ei].w;
for(int j=m; ~j; j--){
int t=-inf;
for(int k=0; k<=j; k++)
t=max(t, f[v][i*w][k]+g[j-k]-i*w*val[v]);
g[j]=t;
}
}
for(int j=0; j<=m; j++) f[u][i][j]=g[j]+i*val[u];
}
cklp(f[u], u);
}
int dp[M];
signed main(){
rd(n); rd(m);
for(int i=1; i<=n; i++){
rd(val[i]);
char opt; cin>>opt;
if(opt=='A'){
int c; cin>>c;
for(int j=1,v,w; j<=c; j++){
rd(v); rd(w); ade(i,v,w);
in[v]++;
}
}
else{
rd(Cost[i]); rd(Lim[i]);
}
}
memset(dp,~63,sizeof(dp)); dp[0]=0;
for(int i=1; i<=n; i++){
if(in[i]) continue;
dfs(i);
for(int j=m; ~j; j--){
for(int k=0; k<=j; k++){
dp[j]=max(dp[j], dp[j-k]+f[i][0][k]);
}
}
}
int ans=0;
for(int i=0; i<=m; i++) ans=max(ans, dp[i]);
printf("%d\n",ans);
return 0;
}