[BZOJ1017][树形DP][背包DP]JSOI2008:魔兽地图DotR

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/89039888

BZOJ1017

每个装备可以直接贡献,也可以用于合成
f [ i ] [ j ] [ k ] f[i][j][k] 表示第 i i 件装备, j j 件用于合成,花费 k k 元可以获得的最大力量值
首先处理出每个高级物品能够购买的上限 l i m [ i ] lim[i] 和价格 m o n [ i ] mon[i]
枚举每个物品购买的数量 l l
f f 数组不好直接转移,设 g [ i ] [ j ] g[i][j] 表示当前子树的前 i i 个子树,花费 j j 元的最大值,转移就是
g [ t o t ] [ j ] = m a x ( g [ t o t ] [ j ] , g [ t o t 1 ] [ j k ] + f [ t o [ i ] ] [ l n e d [ i ] ] [ k ] ) ; g[tot][j]=max(g[tot][j],g[tot-1][j-k]+f[to[i]][l*ned[i]][k]);
然后 f f 的转移就出来了: f [ x ] [ i ] [ j ] = m a x ( f [ x ] [ i ] [ j ] , g [ t o t ] [ j ] + p o w e r [ x ] ( l i ) ) ; f[x][i][j]=max(f[x][i][j],g[tot][j]+power[x]*(l-i));
最后,因为这实际上是一片森林,所以再背包一次选最大值

P.S.实际上BZOJ第8个点跑的很慢,不过我看网上的题解很多都这样

Code:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast)
#include<bits/stdc++.h>
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int N=55,M=2005,INF=1e9;
int vis[N<<1],head[N<<1],nxt[N<<1],tot=0,ned[N<<1],in[N];
inline void add(int x,int y,int w){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;ned[tot]=w;++in[y];}
int f[N][N<<1][M],g[N][M],dp[N][M];
int lim[N],val[N],mon[M];
int n,m,cnt;
char c;
void dfs(int x){
	if(!head[x]){
		lim[x]=min(lim[x],m/mon[x]);
		for(int i=0;i<=lim[x];i++)
			for(int j=i;j<=lim[x];j++)
				f[x][i][j*mon[x]]=(j-i)*val[x];
		return;
	}
	lim[x]=INF;
	for(int i=head[x];i;i=nxt[i]){
		dfs(vis[i]);
		lim[x]=min(lim[x],lim[vis[i]]/ned[i]);
		mon[x]+=ned[i]*mon[vis[i]];
	}
	lim[x]=min(lim[x],m/mon[x]);
	memset(g,-0x3f3f3f3f,sizeof(g));
	g[0][0]=0;
	for(int l=lim[x];~l;l--){
		int cur=0;
		for(int i=head[x];i;i=nxt[i]){
			++cur;
			for(int j=0;j<=m;j++)
				for(int k=0;k<=j;k++)
					g[cur][j]=max(g[cur][j],g[cur-1][j-k]+f[vis[i]][l*ned[i]][k]);
		}
		for(int i=0;i<=l;i++)
			for(int j=0;j<=m;j++)
				f[x][i][j]=max(f[x][i][j],g[cur][j]+val[x]*(l-i));
	}
}
inline void backpack(int now){
	for(int i=0;i<=m;i++)
		for(int j=0;j<=i;j++)
			for(int k=0;k<=lim[now];k++)
				dp[cnt][i]=max(dp[cnt][i],dp[cnt-1][j]+f[now][k][i-j]);
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++){
		val[i]=read();
		c=gc();
		if(c=='B') mon[i]=read(),lim[i]=read();
		else{
			int num=read();
			for(int v,need,j=1;j<=num;j++) v=read(),need=read(),add(i,v,need);
		}
	}
	memset(f,-0x3f3f3f3f,sizeof(f));
	for(int now=1;now<=n;now++) if(!in[now]) dfs(now),++cnt,backpack(now);
	int ans=0;for(int i=0;i<=m;i++) ans=max(ans,dp[cnt][i]);
	cout<<ans;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/89039888