想要弄清楚这个问题,请认真读完每一句
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;
}
}