PTA 7-3 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个整数。第三行包含代表每个物品体积的n个整数。
输出格式:
每组案例一行,只输出一个数字,表示jzk可以获得的最大能量。
输入样例:
在这里给出一组输入。例如:
1
5 10
1 2 3 4 5
5 4 3 2 1
结尾无空行
输出样例:
在这里给出相应的输出。例如:
14
结尾无空行
TIPS:
(包容量是10)可以带第2,3,4,5,个食物,2 + 3 +4 +5 = 14
背包思路:
(本来用的递归,但是tt了,所以不得不改用递推55555555555555)
用二维数组其实更好理解,横坐标为当前剩余内存,竖坐标是说明当前行是哪个物品。
然后二维数组里面的值是说明,若是在该剩余内存条件下,最多能装的价值,求二维数组内的值要取决于剩余内存,若剩余内存已经不足以选该行的物品,则该值就等于上一行的值,若是内存够的话,该值要取决于选不选该物体哪个价值更大一点,若是选了该物体,结果就等于内存减去该物品的体积的最大价值加上该物体的价值,若是不选该物体,就等于上一行所代表的没选该物体在该内存下能装的最大价值,两种情况哪种价值大,就留下哪个值。
但是用二维数组的话内存可能超出限制。所以我用了一维数组,因为某一行只看一次,看完那一次就再也用不到了,所以留着也没啥用,但是要是用一维数组滚动存取的话,需要从内存最大开始循环,因为某一点的值取决于上一行该点的值和上一行前面的某个值。所以后面的值用完之后前面的的值求解是用不到的,所以用完就可以替换掉。
最后,数组的最后一个值就是最大值,因为它代表的是,该内存下所能装的最大价值,最大内存的最大价值就是我们所要求的。
AC代码:
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int *a,*b;
int n,m;
int sum=0;
int q(int m,int i){
if(i==n){
return 0;
}
if(m>=b[i]){
int t=q(m-b[i],i+1)+a[i];
return max(t,q(m,i+1));
}
else{
return q(m,i+1);
}
}
int max(int a,int b){
if(a>=b){
return a;
}
return b;
}
int main(){
int T;
cin>>T;
for(int qqq=0;qqq<T;qqq++){
// int n,m;//n是食物数目,m是背包容量
cin>>n;
cin>>m;
a=new int[n];
b=new int[n];
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
}
// int **c=new int*[n];
// for(int i=0;i<n;i++){
// c[i]=new int[m];
// }
int *c=new int[m+1];
//memset(c,0,sizeof(c));
for(int i=0;i<m+1;i++){
c[i]=0;
}
for(int j=1;j<n;j++){
for(int i=m;i>0;i--){
if(i>=b[j])
c[i]=max(c[i],c[i-b[j]]+a[j]);
// else{
// c[i]=c[i]
// }
}
}
cout<<c[m]<<endl;
}
}