[笔记] 简单的背包问题及优化

简单的背包问题及优化

“你的背包,让我走的好缓慢” ——陈奕迅


一、0-1背包

最简单的0-1背包问题,顾名思义,就是要么装,要么不装。难度不高,但也有一些很清(zhong)新(suo)脱(zhou)俗(zhi)的技巧来让它更巧妙。

E.G:SQ有N个物品,每个物品都有体积tj[i],价值c[i],有一个背包容积为V,在体积不超过V的前提下,背包中物品的价值最大是多少?

1.平淡无奇de解法一:
设f(i,v),其意义为考虑选择第i件物品和剩余空间时的当前总价值,
所以,容易得出两种情况——

不选第i个物品选第i个物品
f(i-1,v)f(i-1,v-tj[i])+c[i])

则状态转移方程为:f(i,v)=max(f(i-1,v),f(i-1,v-tj[i])+c[i]),答案为f(N,V);

//由于解法一过于基础,在此未给出代码 (´・ω・`)

2.有意思的解法二
注意,在解法一中可以发现,f(i,v)只与f(i-1,v)或f(i-1,v-tj[i])有关联,也就是第i行第v列的格子只与第i-1行更靠左边的格子有关系。
把空间压缩到1维,第i行的格子倒着填,左边还没填的格子一定是保留的上一状态(i-1的状态),这样便可以实现空间优化了。

for(int i=1;i<=N;i++){
	for(int v=V;v>=tj[i];v--){
	//倒着枚举体积,要做减法所以不能减成负的
		f[v]=max(f[v],f[v-tj[i]]+c[i]);
	}
}
ans=f[V];

二、完全背包

E.G:SQ这次有了n种物品,每种物品都有体积tj[i],价值c[i],每种物品数量不限。有一个背包容积为V,在体积不超过V的前提下,背包中物品的价值最大是多少?

先上代码~

for(int i=1;i<=N;i++){
	for(int v=tj[i];v<=V;v++){
	//这次的空间优化需要正着枚举v,注意与0-1背包的区别
		f[v]=max(f[v],f[v-tj[i]]+c[i]);
	}
}
ans=f[V];

完全背包的特点是每种物品可选无限件(✪ω✪),考虑完i物品以后还要继续考虑**“加选一件第i种物品”**这种策略,所以需要一个可能已选入第i种物品的子结果,就可以并且必须采用正向的v=tj[i]~V的顺序循环。

三、多重背包

E.G:SQ再一次有了n种物品,每种物品依然有体积tj[i],价值c[i],但不同的是,每种物品数量n[i]。有一个背包容积为V,在体积不超过V的前提下,背包中物品的价值最大是多少?

看似多了一个参数增加了难度,实则不然——其实只是将0-1背包选择策略的默认的x1改为x k(0~n[i])。所以代码就很容易改出来了——

for(int i=1;i<=N;i++){
	for(int v=0;v<=V;v++){
		for(int k=0;k<=n[i];k++){
			if(k*tj[i]<=v){
			    f[i][v]=max(f[i][v],f[i-1][v-k*tj[i]]+k*c[i]);
			}
		}
	}
}
ans=f[N][V];

简单的背包问题及优化大致就是这样了,下面倾情奉献一道相关题目
=||ヽ( ̄▽ ̄)ノミ|Ю

【问题描述】

在《Harry Potter and the Deathly Hallows》中,Harry Potter他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品,现在给出该种物品的数量、体积、价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常地感谢你。

【输入格式】

第一行有2个整数,物品种数n和背包装载体积v。
  第 2 行到 n+1 行每行3个整数,为第i种物品的数量m、体积w、价值s。.

【输出格式】

仅包含一个整数,即为能拿到的最大的物品价值总和。

【输入样例】

2 10
3 4 3
2 2 5

【输出样例】

13

【数据范围】

对于30%的数据:
  1<=v<=500、1<=n<=2000、1<=m<=10、1<=w<=20、1<=s<=100

对于100%的数据:
  1<=v<=500、1<=n<=2000、1<=m<=5000、1<=w<=20、1<=s<=100

#include<algorithm>
#include<iostream>
#include<fstream>
#include<cstring>
#include<cstdio>
using namespace std;

int f[2005][505]={0};
int n[2005],v[2005],p[2005];

int main(){
	int N,C;
	scanf("%d%d",&N,&C);
	for(int i=1;i<=N;i++){
		scanf("%d%d%d",&n[i],&v[i],&p[i]);
	}
	
	for(int i=1;i<=N;i++){
		for(int c=0;c<=C;c++){
			for(int k=0;k<=min(n[i],c/v[i]);k++){
				f[i][c]=max(f[i][c],f[i-1][c-k*v[i]]+k*p[i]);
			}
		}
	}
	printf("%d",f[N][C]);
	return 0;
}

[转载请标明出处 , 谢谢]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值