完全背包 && 多重背包

12 篇文章 0 订阅

完全背包

Description

有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是p[i]。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。

Input

第一行两个整数为V和N
以下N行,每行两个整数为v[i]和p[i]

Output

体积总和不超过背包容量价值最大值

Sample Input Copy

10 4
2 1
3 3
4 5
7 9

Sample Output Copy

12

HINT

N<=100
V<=1000

多重背包

Description

一个背包,承量有限为W,有n种物体,第i种物体,价值Vi,占用重量为 Wi,且有Ci件,选择物品若干放入背包,使得总重量不超过背包的承重。总价值最大?

Input

第1行,2个整数,N和W中间用空格隔开。N为物品的种类,W为背包的容量。(1 <= N <= 500,1 <= W <= 6000) 第2 - N + 1行,每行3个整数,Wi,Pi和Ci分别是物品体积、价值和数量。(1 <= Wi<=100, Pi <= 1000, 1 <= Ci <= 10)

Output

输出可以容纳的最大价值

Sample Input Copy

5 1000

80 20 4

40 50 9

30 50 7

20 30 6

20 20 1

Sample Output Copy

1060

分析
对于完全背包以及多重背包的讲述,之前也写过一篇blog,其中的多是优化过的,但是博主对优化的过程却总是一知半解,这里边用一些相对暴力但是更便于记忆推到理解的方法
首先是完全背包,在这之前,前面有过1篇对完全背包填充方案计数的blog,有意的者可以去翻看
https://blog.csdn.net/c_uizrp_dzjopkl/article/details/99605716
这里便不多赘述了,毕竟是相同的原理
与其的不同便是要算出最大的价值,所以动态转移方程便变成了max的比较,也就是打擂台
对于不放和放了的可得的价值的打擂台
f[n][m] = max(f[n-1][m],f[n-1][m-w[n]*k]+v[n]*k) (w[n]表示第n个物品的重量,v[n]表示第n个物品的价值,k表示第n个物品放几个)
循环的过程也是一样的
之后便是初始化了
不同于之前的是我们在这里要把价值给带上
也就是 f[1][j] = j/w[1]*v[1];
但是我们不用对0列进行初始化了,因为我们是用不到的

之后便是多重背包了
对于物品的装放,我们需要在 c[i] 和 m/w[i] 之间比较,取较小值
因为一种物品如果要放那么其质量不可以超过 m 所以一种物品,如果可以,我们就全放不然的话就放当前最多的数量,都使利益尽量最大

代码
完全背包

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <math.h>
#include <stdio.h>
#include <queue>
#include <stack>
#include <vector>
using namespace std;

int f[1009][1009],w[1009],v[1009];
int n,m;

int main() {
	scanf("%d %d",&m,&n);
	for (int i = 1; i <= n; i++) scanf("%d %d",&w[i],&v[i]);
	
	for (int j = 1; j <= m; j++) f[1][j] = j/w[1]*v[1]; 
		
	for (int i = 2; i <= n; i++)
		for (int j = 1; j <= m; j++)
			for (int k = 0; k <= j/w[i]; k++)
				f[i][j] = max(f[i][j],f[i-1][j-w[i]*k]+k*v[i]);
	
	printf("%d",f[n][m]); 
	
	return 0;
}

多重背包

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <math.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <deque>
using namespace std;

long long f[1009][6009],w[1009],v[1009],num[1009];
int n,m;

int main() {
	scanf("%d %d",&n,&m);
	for (int i = 1; i <= n; i++) scanf("%d %d %d",&w[i],&v[i],&num[i]);
	
	for (int j = 1; j <= m; j++) f[1][j] = min(j/w[1],num[1])*v[1];
	
	for (int i = 2; i <= n; i++)
		for (int j = 1; j <= m; j++)
			for (int k = 0; k <= min(j/w[i],num[i]); k++)
				f[i][j] = max(f[i][j],f[i-1][j-w[i]*k]+v[i]*k);
		
	printf("%lld",f[n][m]);
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值