@@ -750,8 +750,81 @@ function fib(n) {
750
750
fib (10 )
751
751
```
752
752
753
+ ##0 - 1背包问题
753
754
755
+ 该问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。每个问题只能放入至多一次。
754
756
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
+ ```
756
830
757
- 0-1背包
0 commit comments