主要是填充一个二维数组,按照当前物品放入背包和不放入背包动态计算。
假设有一个容量为10的背包和6件物品(v代表价值,w代表重量):
let volumes = 10;
let goods = [
{ w: 3, v: 4 },
{ w: 2, v: 3 },
{ w: 1, v: 2 },
{ w: 5, v: 8 },
{ w: 6, v: 10 },
{ w: 8, v: 14 }
];
要把这6件商品装入背包(商品重量不能大于背包容量),达到价值最大。
首先假设只有一个商品(goods[0],{w: 3, v: 4}
)可以选择:
当背包容量为1的时候:装不下这个物品,此时背包中物品价值为0;
当背包容量为2的时候:装不下这个物品,价值为0;
当背包容量为3的时候:能装下这个物品,价值为4;
背包容量大于3的时候只有一个物品可以装所以也全部为4;
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
假设又增加了一个商品(goods[1],{w: 2, v: 3}
)可以选择:
当背包容量为1的时候:装不下这个商品,那么背包中物品的价值就与只有一个物品时的价值一样(因为当前物品装不下,所以就相当于只有第1个物品可以选),价值是0;
当背包容量是2的时候:
能装下这个商品,此时我们可以选择要不要装这个物品:
如果不装,则背包的价值就是只有第1个物品可以选择时的价值,背包容量为2时的价值:0。
如果装,则在背包容量为2且只有第1个物品可选的基础上,把背包腾出2个空间,背包价值相当于只有第1个物品可选且背包容量为0时,加上当前物品的价值:3
(这里可能有点绕,我们可以反过来思考,当背包容量为2时,有1、2两个物品可以选时,物品2确定要放入背包,那么背包的价值就是物品2的价值 + 背包容量为背包当前的容量减去物品2的重量(2-2 = 0)时且只有物品1可选时的价值 )
0 < 3,所以当背包容量为2的时候,把物品2放入背包,背包的价值更大。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
0 | 3 | - | - | - | - | - | - | - | - |
当背包容量为3时:
能装下这个商品,选择要不要装这个物品:
如果不装,则背包的价值就是只有1个物品可以选择,背包容量为3时的价值:4。
如果装,则要把背包腾出2的空间,背包要腾出来容量2,背包价值相当于只有一个物品时背包容量为1时,加上当前物品的价值:3
4>3,所以当背包容量为3的时候,把物品2放入背包,背包的价值更大。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
0 | 3 | 4 | - | - | - | - | - | - | - |
抽象成通用的逻辑:
当前物品是否放入包中,取决于把背包腾出当前物品的容量时的价值 + 当前物品的价值 是否大于 不放当前物品时背包的价值。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 | 7 | 7 |
2 | 3 | 5 | 6 | 7 | 9 | 9 | 9 | 9 | 9 |
2 | 3 | 5 | 6 | 8 | 10 | 11 | 13 | 14 | 15 |
2 | 3 | 5 | 6 | 8 | 10 | 12 | 13 | 15 | 16 |
2 | 3 | 5 | 6 | 8 | 10 | 12 | 14 | 16 | 17 |
创建二维数组(为了方便数据处理,这里加上背包容量为0和0个物品可选的情况)
let array = [];
let rowArray = [];
for (let index = 0; index <= volumes; index++) {
rowArray.push(0);
}
for (let index = 0; index <= goods.length; index++) {
array.push(rowArray.slice(0, rowArray.length));
}
创建完后数据:
填充二维数组:
function fullTDArray() {
for (let index = 1; index <= goods.length; index++) {
let good = goods[index - 1];
for (let weight = 1; weight <= volumes; weight++) {
if (weight - good.w < 0 || good.v + array[index - 1][weight - good.w] <= array[index - 1][weight]) {
array[index][weight] = array[index - 1][weight];
} else {
array[index][weight] = good.v + array[index - 1][weight - good.w];
}
}
}
}
所以当有上述六个物品且背包容量为10的时候,背包内物品的最大价值是17.
怎么知道背包中有哪些物品呢?
先从最后一个物品观察:
如果背包中没有最后一个物品,则相当于只有前5个物品并且背包容量为10时的价值,就是array[5][10]: 16 < 17,则说明最后一个物品肯定在背包中。
如果最后一个物品在背包中,则剩下5个物品就相当于是背包容量为(10 - 8,因为最后一个物品在背包中)2时,有5个物品可选的情况:
array[5][2] == array[4][2],说明有第5个物品跟没有第5个物品对背包价值没有影响,所以第5个物品不在背包中,依次类推,第4、3个物品也不在背包中,第2个物品在背包中。
所以背包中的物品是第6个和第2个,背包的价值是17