6.又双叒叕背包模拟

背包模拟

概况

主要对有限背包、完全背包、背包记录方案、有依赖背包进行了考查,重点在于考察学生对于背包模型的灵活运用以及学生对背包板子的熟练度

A.PACK

思路:

二维背包板子,还好数据小

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll dp[1005][1005],t[1005],v[1005],g[1005];
int main(){
	ll V=read(),G=read(),n=read();
	for(int i=1;i<=n;i++){t[i]=read();v[i]=read();g[i]=read();}
	for(int i=1;i<=n;i++)
		for(int j=V;j>=v[i];j--)
			for(int k=G;k>=g[i];k--)
				dp[j][k]=max(dp[j][k],dp[j-v[i]][k-g[i]]+t[i]);
	printf("%lld",dp[V][G]);
	return 0;
}

B.DIABLO

思路:

求解最优值部分为有限背包板子,对于记录方案,这是个我一直以来都没太学会的东西,最后在f神的帮助下完成了,大概思路如下:对于第i件物品,我们记录它在剩余为j被选择时的件数k,然后从总费用开始递归输出,要注意的是这里总费用不一定是给出的,而有可能更小,这时就需要提前处理

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll dp[1005],c[1005],p[1005],w[1005][1005],pre[1005][10005];
void print(int now_n,int now_dp){
	if(now_n==0)return;
	print(now_n-1,now_dp-pre[now_n][now_dp]*c[now_n]);
	printf("%lld\n",pre[now_n][now_dp]);
}
int main(){
	ll n=read(),m=read();
	for(int i=1;i<=n;i++){c[i]=read();p[i]=read();for(int j=1;j<=p[i];j++)w[i][j]=read();}
	for(int i=1;i<=n;i++)
		for(int j=m;j>=c[i];j--)
			for(int k=1;k<=p[i]&&k*c[i]<=j;k++){
				if(dp[j-k*c[i]]+w[i][k]>dp[j]){
					dp[j]=dp[j-k*c[i]]+w[i][k];
					pre[i][j]=k;
				}
			}
	while(dp[m]==dp[m-1]) m--;
	printf("%lld\n",dp[m]);
	print(n,m);
	return 0;
}

收获:

1.背包方案记录
2.递归输出方案

C.MANOR

思路:

显然对于这道题,体力和时间的限制是一定的,每个格子的体力和时间是一定的并且是一致的,于是我们只需要对每个格子的消耗进行预处理,进行有限背包即可

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll dp[1005],c[1005][1005],v[1005][1005],t[1005][1005];
int main(){
	ll n=read(),m=read(),ti=read(),a=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			v[i][j]=read(),c[i][j]=(i+j)*2;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			t[i][j]=read();
	for(int x=1;x<=n;x++)
		for(int y=1;y<=m;y++)
			for(int j=min(ti,a-1);j>=c[x][y];j--)
				for(int k=1;k<=t[x][y]&&k*c[x][y]<=j;k++)
					dp[j]=max(dp[j],dp[j-k*c[x][y]]+k*v[x][y]);
	printf("%lld",dp[min(ti,a-1)]);
	return 0;
}

D.BUDGET

思路:

对于每个附件,我们将其存到主件下面,因为最多有两个附件,所以DP部分直接特判即可。但是需要特别注意输入时编号不是按照主件输入的顺序而是按照所有物件输入的顺序

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
struct goods{ll p,im,num;}a[50005][5];
ll dp[50005];
int main(){
	ll m=read(),N=read(),n=0;
	for(int i=1;i<=N;i++){
		ll x,y,z;
		scanf("%lld%lld%lld",&x,&y,&z);
		if(!z){a[i][0].p=x;a[i][0].im=y;}
		else if(!a[z][1].p){a[z][1].p=x;a[z][1].im=y;}
		else{a[z][2].p=x;a[z][2].im=y;}
	}
	for(int i=1;i<=N;i++){
		for(int j=m;j>=a[i][0].p;j--){
			ll p0=a[i][0].p,p1=a[i][1].p,p2=a[i][2].p;
			ll im0=a[i][0].im,im1=a[i][1].im,im2=a[i][2].im;
			ll num=a[i][0].num;
			dp[j]=max(dp[j],dp[j-p0]+p0*im0);
			if(p0+p1<=j&&im1)dp[j]=max(dp[j],dp[j-p0-p1]+p0*im0+p1*im1);
			if(p0+p2<=j&&im2)dp[j]=max(dp[j],dp[j-p0-p2]+p0*im0+p2*im2);
			if(p0+p1+p2<=j&&im1&&im2)dp[j]=max(dp[j],dp[j-p0-p1-p2]+p0*im0+p1*im1+p2*im2);
		}
	}
	printf("%lld",dp[m]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值