是的,有一种更有效的方法!
动态编程 - 自下而上
方法:不是通过评估所有可能的子集来强制解决问题,而是可以针对每个权重的每个项目迭代地解决问题。举个例子:
假设有四个项目 i[1,2,3,4] 关联权重 w[5,3,4,2]、值 v[60,50,70,30] 和最大权重 w = 5。
我们现在将构造一个二维值数组,它保存了选择某项特定权重时的最大值V[i][w]。
填充数组的算法是:
V[i][w] = max(V[i-1, w], V[i-1, w - w_i] + v_i) OTHERWISE V[i-1, w]
这是做什么的? :
对于每个重量的每个项目,我们首先看是否可以在不超过重量限制的情况下选择项目。如果不是,我们取上述项目在该重量下的值(如果该项目也无法选择,则为 0)。
如果我们可以选择项目,有趣的事情就会发生。如果是这样,如果选择的项大于上面选择项的值,我们选择当前项代替:
(So if V[i-1, w] < V[i-1, w - w_i] + v_i)
对所有 n 个项目和 w 个权重执行此操作,您将获得尽可能高的值。
在上述示例中执行算法时,这将是矩阵:
| w |
0 |
1 |
2 |
3 |
4 |
5 |
| Item 1 |
0 |
0 |
0 |
0 |
0 |
60 |
| Item 2 |
0 |
0 |
0 |
50 |
50 |
60 |
| Item 3 |
0 |
0 |
0 |
50 |
70 |
70 |
| Item 4 |
0 |
0 |
30 |
50 |
70 |
80 |
现在要解决背包问题,我们看看 w = 5 时选择项目的值。我们看到选择项目 4 产生的价值最大。我们还可以看到该值的来源。如果我们选择第 4 项,从权重中减去 2,然后我们落在 w = 3 的列中。然后我们上升一行,因为我们选择了第 4 项并且不能再次选择它。然后我们看了一下第 3 项,但是如果我们从 w = 3 中减去 w_3,我们得到 -1,所以我们知道该列中的值是从上面的行继承的,所以我们查看第 2 行。从w = 3 给出 0,所以我们知道该行/列中的值来自选择第 2 项。这最终告诉我们,值 80 是通过选择第 2 项然后选择第 4 项获得的。
与蛮力方法的 O(2 ^ N) 相比,运行它的复杂度是 O(N * W)。