o-1背包问题和多重背包问题

01背包问题和多重背包问题

A-01背包

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
Output
One integer per line representing the maximum of the total value (this number will be less than 231).
Sample Input

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

Sample Output

14

代码如下:
第一题

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005

int N,V;  //N代表商品个数,V代表背包体积 
int vol[MAXN],val[MAXN];
int dp[MAXN];

int main(){
	int T;
	cin>>T;
	while(T--){
		memset(dp,0,sizeof(dp));
		cin>>N>>V;
		for(int i =0;i<N;i++){
			cin>>val[i];//输入每个物品的价值 
		}
		for(int i=0;i<N;i++){
			cin>>vol[i];  //输入每个物品的体积 
		}
		for(int i=0;i<N;i++){
			for(int j=V;j>=vol[i];j--){
				dp[j] = max(dp[j],dp[j-vol[i]]+val[i]);
			}
		}
		cout<<dp[V]<<endl;
	}
	return 0;
}

B-完全背包

第二题:完全背包问题
 对于吃货来说,过年最幸福的事就是吃了,没有之一!
  但是对于女生来说,卡路里(热量)是天敌啊!
  资深美女湫湫深谙“胖来如山倒,胖去如抽丝”的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌。

  当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量。 

Input
  输入包含多组测试用例。
  每组数据以一个整数n开始,表示每天的食物清单有n种食物。
  接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量。
  最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m。

  [Technical Specification]
  1. 1 <= n <= 100
  2. 0 <= a,b <= 100000
  3. 1 <= m <= 100000

Output
  对每份清单,输出一个整数,即满足卡路里吸收量的同时,湫湫可获得的最大幸福值。
Sample Input

3
3 3
7 7
9 9
10
5
1 1
5 3
10 3
6 8
7 5
6

Sample Output

10
20

代码如下:


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXN 100001
int N,V;
int vol[MAXN],val[MAXN];
int dp[MAXN];
int max(int a,int b){
	return a>b?a:b;
}
int main(){
	while(~scanf("%d",&N)){
		memset(dp,0,sizeof(dp));
		for(int i=0;i<N;i++){
			scanf("%d %d",&val[i],&vol[i]); 
		}
		scanf("%d",&V);
		for(int i=0;i<N;i++){
			//for(int j=V;j>=vol[i];j--)
			 //为何这里不能从后向前,这样不对吗? 
			for(int j=vol[i];j<=V;j++){
				dp[j] = max(dp[j],dp[j-vol[i]]+val[i]);
			}
		}
		printf("%d\n",dp[V]);
		//cout<<dp[V]<<endl;
	}
	
	return 0;
}

完全背包和01背包的区别为
01背包每个物品每次只能取一个,所以可以从表格尾部向前遍历,
完全背包和01背包相似,只是每件物品 可以取无限件。
01背包的基本概念就是有一个容量为V的背包,现在有n件物品,每件物品所占空间为w[i],价值为v[i],问装哪些物品能使得背包中所装物品价值达到最大,01背包的特点就是每件物品只有一件,只放一次这也是他与完全背包的最大的区别,完全背包下面会有所讲解。01背包关键部分也就一个双重循环,下面我具体讲解一下这个双重循环,这也是我看了好久才有的理解。

我感觉举例子更容易理解这个代码,我假设有3件物品,背包的总容量为10,第一件物品所占空间为6,价值为300,第二件物品所占空间为5,价值为200第三件所占空间为4,价值为100,放第一件物品自己可以模拟一遍第二重循环可以让让f[10],f[9],f[8],f[7],f[6]的值都为300,然后开始放第二件物
品我上面五项的值都没有都没变,将放f[5]的值变为200,开始放第三个物品此时放f[10]的值变为400,此时我们已经看出来了,当装第一件物品和第三件物品的时候价值最大为400,看到此处相信你也有一定的了解了,就是每次更新的都是f[10]的值,也就是当前容量为最大的时候所能拥有的最大值是多少,则最后的最大值就是多少。f[j]就表示当前容量为j时背包的最大价值。
for(i=1;i<=n;i++)
for(j=V;j>=w[i];j–)
f[j]=max(f[j],f[j-w[i]]+v[i]);

下面该讲完全背包了,完全背包与01背包的最大区别就是,完全背包是有n种物品,每种物品可以取无线多件,每件物品所占空间为w[i],价值为v[i],问容量为V的的背包中放那些物品价值最大。完全背包也是一个双重循环,下面来具体讲解一下。

先举个例子来模拟一遍代码的运行过程,假设背包的总容量20,有3 15 400 5 200 10 500,表示有3种物品,后面6个数每两数表示这种物品中每件所占的空间,和价值。好下面拿这个例子来模拟一遍代码运行的过程先放第一种物品,内层循环让f[15],f[16],f[17],f[18],f[19],f[20]的值都变为400,然后开始放第二种物品,开始f[5]等于200,循环到j等于10的时候f[10]=400,循环到j等于15的时候f[15]的值为600,循环到j==20,f[20]=800,然后放第三种物品,当 j == 10的时候f[10]的值变为500,j = = 20的时候f[20]的值变为1000,因此,当第三种物品放两件时背包中的所放物品的价值最大。

for(i=1;i<=n;i++)
for(j=w[i];j<=V;j++)
f[j]=max(f[j],f[j-w[i]]+v[i]);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值