如何使用背包算法找到袋子里有哪些元素[而不仅仅是袋子的价值]?
这里我有使用背包算法计算最优值的代码(装箱 NP 难题):
int Knapsack::knapsack(std::vector<Item>& items, int W)
{
size_t n = items.size();
std::vector<std::vector<int> > dp(W + 1, std::vector<int>(n + 1, 0));
for (size_t j = 1; j <= n; j++)
{
for ( int w = 1; w <= W; w++)
{
if (items[j-1].getWeight() <= w)
{
dp[w][j] = std::max(dp[w][j-1], dp[w - items[j-1].getWeight()][j-1] + items[j-1].getWeight());
}
else
{
dp[w][j] = dp[w][j - 1];
}
}
}
return dp[W][n];
}
我还需要显示包中包含的元素。我想创建一个数组来放置所选元素。那么问题来了,我可以在哪一步进行这个选择呢?还有其他更有效的方法来确定哪些物品已被拿走吗?
我希望能够知道为我提供最佳解决方案的项目,而不仅仅是最佳解决方案的价值。
Here I have code which calculates the optimal value using the knapsack algorithm (bin packing NP-hard problem):
int Knapsack::knapsack(std::vector<Item>& items, int W)
{
size_t n = items.size();
std::vector<std::vector<int> > dp(W + 1, std::vector<int>(n + 1, 0));
for (size_t j = 1; j <= n; j++)
{
for ( int w = 1; w <= W; w++)
{
if (items[j-1].getWeight() <= w)
{
dp[w][j] = std::max(dp[w][j-1], dp[w - items[j-1].getWeight()][j-1] + items[j-1].getWeight());
}
else
{
dp[w][j] = dp[w][j - 1];
}
}
}
return dp[W][n];
}
I also need the elements included in the pack to be shown. I want to create an array to put the chosen elements. So the question is, in which step can I perform this selection? Is there any other more efficient way to determine which items have been taken?
I want to be able to know the items that give me the optimal solution, and not just the value of the best solution.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
可以使用矩阵中的数据来获取从矩阵中打包的元素,而无需存储任何其他数据。
伪代码:
其背后的想法是迭代矩阵;如果重量差恰好等于元素的大小,则它在背包中。如果不是,则该物品不在背包中,不带它继续。
Getting the elements you packed from the matrix can be done using the data from the matrix without storing any additional data.
Pseudo code:
The idea behind it is that you iterate the matrix; if the weight difference is exactly the element's size, it is in the knapsack. If it is not, the item is not in the knapsack, go on without it.
只要记住当您添加项目 i 时如何到达 dp[line][i]
Just remember how you got to dp[line][i] when you added item i
用于重建有界 0/1 背包中的物品的算法比该线程中的一些现有代码可能让人相信的要简单。这个答案旨在稍微揭开这个过程的神秘面纱,并提供一个干净、直接的实现以及一个有效的示例。
该方法
从对应于表轴的两个索引开始:初始化为背包容量的
weight
变量和沿项目轴在 DP 查找表上向后循环的索引i
,在索引 1 处停止(该算法使用 i-1 因此在 1 处停止可以避免越界访问)。在循环中,如果
T[weight][i] != T[weight][i-1]
,则将项目i-1
标记为选中,扣除其权重并继续沿着项目轴向后移动。重建的时间复杂度为
O(length(items))
。下面是 Python 伪代码:
示例
例如,考虑背包容量为 9 和这些物品:
通过获取物品 0、1 和 2,最佳值为 15。
DP 查找表
为此运行重建算法:
在初始状态上面,
T[weight][i] == T[weight][i-1]
(15 == 15
) 所以item[i-1]
(item(weight=6, value=4)
) 未被获取。递减i
并尝试具有相同容量的剩余项目。这里,
T[weight][i] != T[weight][i-1]
(7 != 15
) 所以items[i-1]
,即items[2]
或item(weight=4, value=8)
,必须已被获取。将剩余重量减少items[i-1].weight
或9 - 4 = 5
,然后尝试取出item[i-1]
不在图片中。在这种状态下,我们再次有
T[weight][i] != T[weight][i-1]
(2 != 7
) 所以我们必须采取items[i-1]
,即items[1]
或item(weight=3, value=5)
。将剩余重量减少items[i-1].weight
或5 - 3
,然后移至下一个项目。在最后一步中,我们再次有
T[weight][i] != T[weight][i-1]
(0 != 2
) 所以我们必须有采用items[i-1]
,即items[0]
或item(weight=1, value=2)
。将剩余权重减少items[i-1].weight
或2 - 1
,并退出循环,因为i == 0
。C++ 实现
另请参阅
The algorithm for reconstructing items taken in bounded 0/1 knapsack is simpler than some of the existing code in this thread may lead one to believe. This answer aims to demystify the procedure a bit and provide a clean, direct implementation alongside a worked example.
The approach
Begin with two indices respective to the table axes: a
weight
variable initialized to the knapsack capacity and an indexi
that loops backwards over the DP lookup table along the item axis, stopping at index 1 (the algorithm usesi-1
so stopping at 1 avoids an out of bounds access).In the loop, if
T[weight][i] != T[weight][i-1]
, mark itemi-1
as selected, deduct its weight and continue stepping backwards along the item axis.Time complexity of the reconstruction is
O(length(items))
.Here is Python as pseudocode:
Example
For example, consider a knapsack capacity of 9 and these items:
The best value is 15 by taking items 0, 1 and 2.
The DP lookup table is
Run the reconstruction algorithm on this:
In the initial state above,
T[weight][i] == T[weight][i-1]
(15 == 15
) soitem[i-1]
(item(weight=6, value=4)
) wasn't taken. Decrementi
and try the remaining items with the same capacity.Here,
T[weight][i] != T[weight][i-1]
(7 != 15
) soitems[i-1]
, which isitems[2]
, oritem(weight=4, value=8)
, must have been taken. Decrement the weight remaining byitems[i-1].weight
, or9 - 4 = 5
, and try the remaining items with the smaller weight left over after takingitem[i-1]
out of the picture.In this state, we again have
T[weight][i] != T[weight][i-1]
(2 != 7
) so we must have takenitems[i-1]
, which isitems[1]
, oritem(weight=3, value=5)
. Decrement the weight remaining byitems[i-1].weight
, or5 - 3
, and move to the next item.In this last step, we again have
T[weight][i] != T[weight][i-1]
(0 != 2
) so we must have takenitems[i-1]
, which isitems[0]
, oritem(weight=1, value=2)
. Decrement the weight remaining byitems[i-1].weight
, or2 - 1
, and exit the loop becausei == 0
.C++ implementation
See also
这是 Julia 的实现:
Here is a julia implementation: