01背包问题(超不详细简易版笔记)

其实背包问题大一的时候C++老师就一直念叨,但是奈何懒和无知,老师讲的时候就总觉得soeasy。
老师原话解释如下:你的背包容积为M,然后学校某社团搞活动发零食(见者有份)一共有N种零食,每种每人只能拿一包,第i种体积为w[i],好吃程度为d[i],你要怎么拿才能拿到有多又好吃的?当然是一包一包的选择拿或者不拿,然后再比较拿了或者不拿的好吃程度(在背包容积范围内)最后就可以了呀。
当时就觉得:哦!不就是做个比较吗?然后现在遇到了相似问题才发现我真的太无知了。好了,废话到此结束。接下来就是刚刚看网课学到的笔记了。

--------------------------------分割线---------------------------------
有N件商品,购物车容积为M,第i件商品的体积为w[i],价值为d[i],将哪些商品装入购物车可以使价值总和最大,每件商品有仅有一件,可选择拿或者不拿。数据如下:
来源于北京航天航空工业大学mooc(图片来自中国大学mooc北航《算法设计与分析》)

首先我们可以设置一个二维数组 F[i][j] 表示取前i种商品,使总体积不大于j,总价值为F[i][j]。
如果不取第i件商品,则总价值为F[i-1][j];
如果取第i件商品,则总价值为(F[i-1][j-w[i]]+d[i]);
取两者最优就是取两者价值最大的,所以可以推出递推式:
F[i][j] = max( F[i-1][j] , F[i-1][j-w[i]]+d[i])

但是这样开二维数组容易超内存,可以采用滚动数组的方式,把二维数组优化为一维数组F[v],v表示背包容积。因为新求出的F[v]的值会覆盖F[v+1]的值,所以 v 要从M开始递减。
优化后如果不取第i件商品,总价值为F[v];
如果取第i件商品,则总价值为F[v-w[i]]+d[i];
可以得到递推式为:
F[v]=max(F[v],F[v-w[i]]+d[i])

完整代码如下(求解图片上的问题):

#include <iostream>
#include <string>
#include <algorithm> 
#define N 100000
using namespace std;
int main()
{
	int n,m,w[N],d[N],f[N];//共有n件物品背包体积m,体积数组w[],价值数组d[]
	cin>>n>>m;
	int i,v; 
	for(i=1;i<=n;i++)
		cin>>d[i]>>w[i];
		
	for(i=1;i<=n;i++)
		for(v=m;v>=w[i];--v)
			f[v]=max(f[v],f[v-w[i]]+d[i]); 
			
	cout<<f[m]<<endl;//此时最优解是f[m]不是f[v]
	/*可以用输出f[]的方式检验最优解为f[m]
	for(i=1;i<=m;i++)
	{
		cout<<f[i]<<endl;
	}
	*/
	return 0;
}

通过蛮力枚举可以得到最优解:
在这里插入图片描述(图片来自中国大学mooc北航《算法设计与分析》)

运行结果如下:
在这里插入图片描述
其实也并没有理解的很透彻,所有要是有解释不当的地方,还请各位大佬指出来,谢谢啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值