0/1背包问题

想要弄清楚这个问题,请认真读完每一句

0/1的意思就是判断一个物体到底要不要放到包里面

我用以下例子说明:
重量:2 3 4 5
价值:3 4 5 6
(重量与价值上下一一对应)

1.背包容量为1时什么都装不了;
2.背包容量为2时能装下价值为3的一个物品;
3.背包容量为3时能装下价值为3或者为4的物品,由于要尽可能多的装价值高的物品,所以只装重量3,价值4的物品,而不是去选重量2,价值3的物品。。。

以上为人脑思维

现在用编程的思想,我们需要做一个表格,什么表格呢?
这个表格可以表示以当前背包的空间,能装下的所有物品,价值总和最大是多少

这个表格就是解决0/1背包的关键。

以上述例子,背包空间最大为8,一步一步可以算出下表。
其中的i表示:在前i个物品里面选要装入的。i=0表示没有物品要装入,i=3表示前3个物品里面选哪个要装入。
最后求得最大价值。

在这里插入图片描述
这样可以显而易见地得到背包空间为8时,有以上例子中的4个物品要装,能装到的价值最大总和为10。即选->(重量3价值4的物品)加上(重量5价值6的物品),总价值为10,最大。

最后问题来了!

怎么通过编程求得这个表格???

  for (int i = 1; i <= n; i++)
   for (int j = h; j>=w[i]; j--)
    ex[j] = max(ex[j], ex[j - w[i]] + v[i]);

这个就是算法的关键之处!
ex数组表示背包。ex[j]表示背包容量为j时,我们能装下的最大价值。

先看内层循环,

采用倒序,先求背包容量最大值时,是否装入重量为w[i]的物品
当然,能装下,肯定要装。
装了该物品,背包的容量就要相应的减去该物品的重量。
这也就是j - w[i]的意义。

ex[ j - w[i] ] 就表示,背包在容量为j - w[i]时,能装下的最大价值。

ex[ j - w[i] ] + v[i] 就表示,装了该物品后背包里面的最大价值。

最后比较(未装该物品的背包总价值)和(装了该物品的背包总价值)哪个更大,更大的就存入到这个ex数组里面。
很多人会说,这不是废话吗?肯定装了物品价值更大啊,可是你有没有考虑到,该物品价值为负数的时候。

再看外层循环

i不断增加,i每增加一,就是在判断,这些背包容量j里面,装物品i与不装物品i,价值会不会变大。
通过这样的几层循环,就能求得这个表格。

以下为代码:

#include "pch.h"
#include <iostream>
#include<algorithm>
using namespace std;
int n, h;  //n为n个物品,h为背包的空间
int w[1002], v[1002];//w为物品的重量,v为物品的价值
int ex[1002];  //ex[h]为当背包的空间为h时,能装下总价值最大的物品
int main()
{
 int T;  //T组数据
 cin >> T;
 while (T--)
 {
  cin >> n;
  cin >> h;
  for (int i=1; i <= n; i++)
   cin >> v[i];
  for (int i = 1; i <= n; i++)
   cin >> w[i];
  memset(ex, 0, sizeof(ex));  //初始化ex数组
  for (int i = 1; i <= n; i++)
   for (int j = h; j>=w[i]; j--)//j>=w[i]保证了背包还能装下第i个物品
    ex[j] = max(ex[j], ex[j - w[i]] + v[i]);
    //ex[j]变为->ex[j]和(ex[j-第i个物品的重量]+第i个物品的价值)二者中值更大的一个
  cout << ex[h] << endl;
 }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值