PTA 01背包

题目

事情是这样的,jzk要去爬山,但是他的包容量有限,可是他需要非常多的能量,要不然就很容易饿。 第一行给出jzk准备爬几次山。 每次爬山都会带新的包(因为jzk每用一个包都会被zwg抢过去),和准备新的食物(因为每次剩下来的都被zwg吃了)。 下一行给你这一次食物的数目n,和背包容量k, 接下来的一行给出n个食物的能量,再一行给出n个食物的大小(占背包的容量)。 请帮助jzk计算他最多可以带多少能量的食物去爬山。输出可以携带食物的最大能量和。 (n,m<1000) 能量和食物均小于40000

输入

第一行包含整数T,表示有T组案例。
接着是T组案例,每组案例三行,第一行包含两个整数N,M,( N ≤ 1000 , M ≤ 1000 N\le1000,M\le1000 N1000M1000),表示物品数量和袋子的体积。第二行包含表示每个物品能量的n个整数。第三行包含代表每个物品体积的n个整数。

输出

每组案例一行,只输出一个数字,表示jzk可以获得的最大能量。

样例输入

1
5 10
1 2 3 4 5
5 4 3 2 1

样例输出

14

题目分析

本题是很经典的01背包问题,对于这方面的问题也有很多解答,这里就说说我这个程序的一点基本思想以及处理的关键点。
处理01背包,主要是在分配价值与物体体积之间谋求最优解。在同等体积下,算出我们能够获得的最大价值,再利用已知的体积下的最大价值去完成对更大体积下的最大价值的更新。
比方说:对{物体体积,物体价值}={3,2},{2,3}。现有空间大小为5。

12345
00000

现在什么都没装入,因此在前n个大小的空间中价值均为0。现在取出物体1,装入。

12345
00222

可以发现,装入物体1之后,用3个空间装,价值为2,用5个空间装,价值同样为2.
那么我们在装入物体1的前提下再装入物体2。这个时候我们就会遇到一个问题,那就是:在物体1进入背包后,在剩余空间不够的情况下,我们如何处理物体2?
是将物体1取出后放入物体2,还是放弃放入物体2?
这个时候明显就出现了价值比较,对应的选择取决于选择后的价值。
v a l u e [ i ] = { m a x ( v a l u e [ i ] , v a l u e [ i − v o l u m n [ k ] ] + w [ k ] ) i f i ≥ v o l u m n [ k ] v a l u e [ i ] i f i < v o l u m n [ k ] value[i]=\begin{cases} max(value[i],value[i-volumn[k]]+w[k]) &if&i\ge volumn[k]\\ value[i] &if &i<volumn[k] \end{cases} value[i]={max(value[i],value[ivolumn[k]]+w[k])value[i]ififivolumn[k]i<volumn[k]
现在将物体2放入,得到value的数组

12345
03335

注意点:在向背包内放入物品时,需要由最大空间开始存放,直到放不下为止。原因是在进行价值比较时,我们是将当前状态下剩余空间下的最大价值加上放入物品价值后与当前状态比较,但是剩余空间下的最大价值中还没有放入该物品。
若是从小空间开始逐个尝试,则很有可能会造成一件物品放入了多次的情况。

代码

#include<iostream>
#include<cstring>
using namespace std;
int value[1005];//存储物体价值
int volumn[1005];//存储物体体积
int f[1005];//存储在该体积下的最大放入物体的价值
int n,m;

int main(){
	int T;
	cin >> T;
	while(T--){
		cin >> n >> m;
		for(int i = 1;i<=n;++i) scanf("%d",&value[i]);
		for(int i = 1;i<=n;++i) scanf("%d",&volumn[i]);
		for(int i = 1;i<=n;++i){
			for(int j = m;j>=0;--j){
				if(volumn[i]<=j){
					f[j]=max(f[j],f[j-volumn[i]]+value[i]);//价值比较
				}
			}
		}
		cout << f[m]<<endl;
		memset(value,0,sizeof(value));
		memset(volumn,0,sizeof(volumn));
		memset(f,0,sizeof(f));
	}
	return 0;
}

运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

registor11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值