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

时间:2017-01-28 15:43:56

标签: algorithm breadth-first-search

我遇到了一个名为Knapsack的有趣问题。你有一个项目列表,它们都有一个值和一个权重。然后,您必须找到最大化对象总和值的项目组合,并保持在一定限度内。我在某处看到这是一个搜索问题,您可以使用不同的搜索算法。现在我试图用广度优先实现它。

在维基百科上找到的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队列。对于每个选定的项目,我有两个选择:我是否采取该项目。 无论如何,具体来说:我不明白,在我的上下文中,上面的伪代码是:

  • 当我选择一个项目时,我是否将其两次推入队列并将其中一个标记为已使用且一个未使用?
  • 我如何知道当前是否是目标?我假设它的东西就像没有更多的节点要探索,这意味着我们在叶节点。但是会有很多叶子节点,所以我选择哪一个以及如何?
  • 与电流相邻是什么意思?如果我只有一个列表或一个项目数组(项目有ID,权重和值),我怎么知道哪个是相邻的?

1 个答案:

答案 0 :(得分:0)

假设您有4个不同的项目。然后,您正在搜索的图表是这样的超立方体(图片来自Yury Chebiryak):

Gray code hypercube

节点上的二进制数是所有可能的背包, n 中的0表示项目 n 不在背包中,并且1意思是,所以例如0000表示空背包,1001表示包含第一个项目和第4个项目的背包,依此类推。

在每个步骤中,您从队列中删除当前节点,如果它不是目标,则通过查找与当前逐个项目不同的所有背包来构建相邻节点。我已经去过了。因此,例如,如果当前节点为1001,则构建节点0001,1101,1011和1000.然后将这些节点添加到队列中。

如果你正在寻找一个足够好的目标,那么这个目标只有意义。解决方案,而不是最佳解决方案。要确定当前节点是否是目标,您只需计算当前背包的值并将其与目标值进行比较。

如果您想要最佳解决方案,那么广度优先搜索对您没有帮助,因为您需要浏览图表中的每个节点。 Dynamic programmingbacktracking(这是一种Depth First Search)可以减少搜索空间。

如果你想要一个足够好的"解决方案,然后FIFO branch-and-boundhill climbing(从随机背包开始)是使用广度优先搜索的有效方法。