使用广度优先搜索的非递归 0/1 背包算法

Non-recursive 0/1 Knapsack algorithm using Breadth-first Search

我遇到了一个有趣的问题,叫做背包。您有一个项目列表,所有项目都有一个值和一个重量。然后,您必须找到使求和对象的价值最大化的项目组合,并保持在一定限度内。我在某处看到这是一个搜索问题,您可以使用不同的搜索算法。现在我尝试用广度优先来实现它。

在维基百科上找到的BFS伪算法如下:

Breadth-First-Search(Graph, root):

create empty set S
create empty queue Q      

root.parent = NIL
Q.enqueue(root)                      

while Q is not empty:
    current = Q.dequeue()
    if current is the goal
        return current
    for each node n that is adjacent to current:
        if n is not in S:
            add n to S
            n.parent = current
            Q.enqueue(n)

我真的很想了解如何将其应用于背包问题。

据我了解,这是关于建造一棵树。我需要一次扩展和探索一个级别的每个节点。对于 BFS,我需要一个 FIFO 队列。对于 selected 的每个项目,我有两个选择:要么我拿走这个项目,要么不拿。 无论如何,具体来说:在我的上下文中,上面的伪代码我不明白的是:

假设您有 4 件不同的物品。那么你正在搜索的图形是一个像这样的超立方体(图像来自Yury Chebiryak):

节点处的二进制数是所有可能的背包,第n位为0表示第n项是不在背包中,1 表示在背包中,例如 0000 表示背包是空的,1001 表示背包中包含第一项和第四项,依此类推。

每一步从队列中移除当前节点,如果不是目标,则通过逐一找到所有与当前节点不同的未访问过的背包来构造相邻节点已经。例如,如果当前节点是 1001,您将构建节点 0001、1101、1011 和 1000。然后将这些节点添加到队列中。

只有在寻找 "good enough" 解决方案而不是最佳解决方案时,目标才有意义。要确定当前节点是否是目标,您只需计算出当前背包的值并将其与目标值进行比较。

如果您想要最佳 解决方案,那么广度优先搜索对您没有帮助,因为您需要探索图中的每个节点。 Dynamic programming or backtracking (which is a kind of Depth First Search) 将允许您减少搜索 space.

如果您想要 "good enough" 解决方案,那么 FIFO branch-and-bound or hill climbing(从随机背包开始)是使用 breadth-first 搜索的有效方法。