动态规划基础——0/1背包问题

0/1背包问题的描述

这种背包问题是最基础的一类背包问题。只要掌握的这种,后面的也就是大同小异了。因此,我在这个问题上将讲得非常详细。
0/1背包问题就是存在一个背包有着固定的容积M,物品有自己的质量w和价值c,当然,每一个物品都只有一件,而且不可拆分。你的任务是:把这些东西装入这个背包,使装入物品的价值最大。
首先,贪心算法只有在物品可分的时候才会生效(求性价比),搜索这个指数级的复杂度不解释!
所以我们选择动态规划。

0/1背包问题的代码和样例输入输出

先上代码

#include<iostream>
#include<algorithm>
using namespace std;
const int maxm=1005;
int M,n,f[maxm];
int w[maxm],c[maxm];
int main(){
	cin>>M>>n;
	for(int i=1;i<=n;i++) cin>>w[i]>>c[i];
	for(int i=1;i<=n;i++){  //第一层for循环
		for(int j=M;j>=w[i];j--){  //第二层for循环
			f[j]=max(f[j],f[j-w[i]]+c[i]);
		}
	}
	cout<<f[M]<<endl;
	return 0;
} 
样例输入样例输出
10 412
2 1
3 3
4 5
7 9

0/1背包问题详解

上诉代码的第一层for循环的目的是控制本次选择的物品,第二层循环在于选择当前物品时,在背包体积为j时的最大体积。f[n]表示的就是在背包体积为n时可以装下的最大价值。这道题难在这个状态转移方程: f [ j ] = m a x ( f [ j ] , f [ j - w [ i ] ] + c [ i ] ) ——这是什么鬼?i这个变量就相当于是被选择的这个物品的编号,比如 w [ i ] 就是第 i 个物品的重量。
我们从背包体积为10开始装入物品,因为你会发现如果从小体积往大体积装载,大体积就会受到小体积 f 的影响,因为大的总是拿小的更新自己的 f 值。如果无法理解这句话,就请看模拟吧!
首先我们根据输入,填入数据。没错的话是酱紫:
在这里插入图片描述
然后进入第一层for循环,选择了第一个物品。
我们从第十个开始,也就是 f [ 1 0 ] 开始,填入的数据就是 1 ,因为我们执行了这句话f [ 10 ] = m a x ( f [ 10 ] , f [ 10 - w [ 1 ] ] + c [ 1 ] ) ,这句话的实际意思是:我们要不要拿这个物品,拿了会不会增加背包体积为10的时候的最大价值,所以我们尝试着询问到背包体积为8时候的最大价值,为什么不选更小的呢?1号物品的体积刚好是2,所以10减去2空出来的8的体积才有可能是装下的最大价值。试想,假若现在有一个物品的质量是1,然后你却询问7的,那这个质量为1的岂不是没装上去你就算了10的体积,等于我们浪费了一个体积!而且,你没事情把他取小掉干什么?我们正需要大量的体积来装更多的物品提升总价值啊!!!
总之,我们去询问体积为8的最大价值,其实就是假设我们选了1号物品的意思,所以我们自然也要在后面加上1号物品的价值。然后跟原来的体积为10的比较。谁大就取谁。然后发现f [ 10 - w [ 1 ] ] + c [ 1 ] 是1,f [ 10 ] 是0,取前者。如图:
在这里插入图片描述
然后 j = 9 了,然后发现f [ 9 - w [ 1 ] ] + c [ 1 ] 是1,f [ 9 ] 是0,取前者。,选取第一个物品走完一轮后,就都是1了。如下图:
在这里插入图片描述
你会问,为什么第一个这么孤单只有0呢?因为,第一个体积只有1,比物品本身还要小,所以我们就不循环啦!反正都是装不下的。不信你看看第二层循环就是这么写的:f o r ( i n t j = M ; j > = w [ i ] ; j - - )
接下来第二轮,我们选取了第二个物品啦。还是 j = M 开始循环,我们现在背包体积为10的时候,可以装下最大价值为1,然而,经过这一步的时候( f [ j ] = m a x ( f [ j ] , f [ j - w [ i ] ] + c [ i ] )),我们发现多了一个物品,那10的体积还可以继续装吧!
所以我们的f [ 10 ] = m a x ( f [ 10 ] , f [ 10 - w [ 2 ] ] + c [ 2 ] )这一步, f [ 10 - w [ 2 ] ] + c [ 2 ] 就是询问:假如我拿了2号物品,背包体积为10的时候最大价值会增加吗?所以假设我们装了,那剩余体积就是10 - w [ 2 ]没错吧,然后我们看看当前状态下最大可以装多少:那就是f [ 10 - w [ 2 ] ] 没错吧。但是你总不能占了我体积又没有价值吧,所以顺理成章把价值也给带上,那就是 f [ 10 - w [ 2 ] ] + c [ 2 ] ,然后跟原来的f [ 10 ]做一个比较。发现,我们假设的东西好像还大一点,那就把f [ 10 ]换成我们假设的吧!欢乐~
于是f [ 10 ]就愉快地更新了。
在这里插入图片描述
这样不断更新下去,第二轮完毕以后就是酱紫:
在这里插入图片描述
然后是第三轮完毕以后的效果:
在这里插入图片描述
第四轮,也就是最后一轮结束后的效果:
在这里插入图片描述
至此,动态规划结束。直接输出 f [ 1 0 ] 即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值