Skip to content

Commit a13e6e0

Browse files
author
YuChengKai
committed
0-1背包问题
1 parent 5e2677d commit a13e6e0

File tree

1 file changed

+75
-2
lines changed

1 file changed

+75
-2
lines changed

Algorithm/algorithm-ch.md

+75-2
Original file line numberDiff line numberDiff line change
@@ -750,8 +750,81 @@ function fib(n) {
750750
fib(10)
751751
```
752752

753+
##0 - 1背包问题
753754

755+
该问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。每个问题只能放入至多一次。
754756

755-
343
757+
假设我们有以下物品
758+
759+
| 物品 ID / 重量 | 价值 |
760+
| :------------: | :--: |
761+
| 1 | 3 |
762+
| 2 | 7 |
763+
| 3 | 12 |
764+
765+
对于一个总容量为 5 的背包来说,我们可以放入重量 2 和 3 的物品来达到背包内的物品总价值最高。
766+
767+
对于这个问题来说,子问题就两个,分别是放物品和不放物品,可以通过以下表格来理解子问题
768+
769+
| 物品 ID / 剩余容量 | 0 | 1 | 2 | 3 | 4 | 5 |
770+
| :----------------: | :--: | :--: | :--: | :--: | :--: | :--: |
771+
| 1 | 0 | 3 | 3 | 3 | 3 | 3 |
772+
| 2 | 0 | 3 | 7 | 10 | 10 | 10 |
773+
| 3 | 0 | 3 | 7 | 12 | 15 | 19 |
774+
775+
直接来分析能放三种物品的情况,也就是最后一行
776+
777+
- 当容量少于 3 时,只取上一行对应的数据,因为当前容量不能容纳物品 3
778+
- 当容量 为 3 时,考虑两种情况,分别为放入物品 3 和不放物品 3
779+
- 不放物品 3 的情况下,总价值为 10
780+
- 放入物品 3 的情况下,总价值为 12,所以应该放入物品 3
781+
- 当容量 为 4 时,考虑两种情况,分别为放入物品 3 和不放物品 3
782+
- 不放物品 3 的情况下,总价值为 10
783+
- 放入物品 3 的情况下,和放入物品 1 的价值相加,得出总价值为 15,所以应该放入物品 3
784+
- 当容量 为 5 时,考虑两种情况,分别为放入物品 3 和不放物品 3
785+
- 不放物品 3 的情况下,总价值为 10
786+
- 放入物品 3 的情况下,和放入物品 2 的价值相加,得出总价值为 19,所以应该放入物品 3
787+
788+
以下代码对照上表更容易理解
789+
790+
```js
791+
/**
792+
* @param {*} w 物品重量
793+
* @param {*} v 物品价值
794+
* @param {*} C 总容量
795+
* @returns
796+
*/
797+
function knapsack(w, v, C) {
798+
let length = w.length
799+
if (length === 0) return 0
800+
801+
// 对照表格,生成的二维数组,第一维代表物品,第二维代表背包剩余容量
802+
// 第二维中的元素代表背包物品总价值
803+
let array = new Array(length).fill(new Array(C + 1).fill(null))
804+
805+
// 完成底部子问题的解
806+
for (let i = 0; i <= C; i++) {
807+
// 对照表格第一行, array[0] 代表物品 1
808+
// i 代表剩余总容量
809+
// 当剩余总容量大于物品 1 的重量时,记录下背包物品总价值,否则价值为 0
810+
array[0][i] = i >= w[0] ? v[0] : 0
811+
}
812+
813+
// 自底向上开始解决子问题,从物品 2 开始
814+
for (let i = 1; i < length; i++) {
815+
for (let j = 0; j <= C; j++) {
816+
// 这里求解子问题,分别为不放当前物品和放当前物品
817+
// 先求不放当前物品的背包总价值,这里的值也就是对应表格中上一行对应的值
818+
array[i][j] = array[i - 1][j]
819+
// 判断当前剩余容量是否可以放入当前物品
820+
if (j >= w[i]) {
821+
// 可以放入的话,就比大小
822+
// 放入当前物品和不放入当前物品,哪个背包总价值大
823+
array[i][j] = Math.max(array[i][j], v[i] + array[i - 1][j - w[i]])
824+
}
825+
}
826+
}
827+
return array[length - 1][C]
828+
}
829+
```
756830

757-
0-1背包

0 commit comments

Comments
 (0)