【问题标题】:Calculating items included in branch and bound knapsack计算分支和绑定背包中包含的物品
【发布时间】:2013-04-10 13:15:11
【问题描述】:

使用分支定界算法,我已经评估了一组给定项目的最佳利润,但现在我想找出哪些项目包含在这个最佳解决方案中。我正在评估最佳背包的利润值如下(改编自here):

import Queue

class Node:
    def __init__(self, level, profit, weight):
        self.level = level # The level within the tree (depth)
        self.profit = profit # The total profit
        self.weight = weight # The total weight

def solveKnapsack(weights, profits, knapsackSize):
    numItems = len(weights)
    queue = Queue.Queue()
    root = Node(-1, 0, 0)    
    queue.put(root)

    maxProfit = 0
    bound = 0
    while not queue.empty():
        v = queue.get() # Get the next item on the queue

        uLevel = v.level + 1 
        u = Node(uLevel, v.profit + e[uLevel][1], v.weight + e[uLevel][0])

        bound = getBound(u, numItems, knapsackSize, weights, profits)

        if u.weight <= knapsackSize and u.profit > maxProfit:
            maxProfit = uProfit

        if bound > maxProfit:    
            queue.put(u)

        u = Node(uLevel, v.profit, v.weight)
        bound = getBound(u, numItems, knapsackSize, weights, profits)

        if (bound > maxProfit):
            queue.put(u)
    return maxProfit

# This is essentially the brute force solution to the fractional knapsack
def getBound(u, numItems, knapsackSize, weight, profit):
    if u.weight >= knapsackSize: return 0
    else:
        upperBound = u.profit
        totalWeight = u.weight
        j = u.level + 1
        while j < numItems and totalWeight + weight[j] <= C:
            upperBound += profit[j]
            totalWeight += weights[j]
            j += 1
        if j < numItems:
            result += (C - totalWeight) * profit[j]/weight[j]
        return upperBound 

那么,我怎样才能得到构成最优解的项目,而不仅仅是利润?

【问题讨论】:

  • 我不确定这是否会最大程度地放松项目约束。

标签: python tree binary-tree knapsack-problem branch-and-bound


【解决方案1】:

我以您的代码为起点完成了这项工作。我将Node 类定义为:

class Node:
    def __init__(self, level, profit, weight, bound, contains):
        self.level = level          # current level of our node
        self.profit = profit
        self.weight = weight        
        self.bound = bound          # max (optimistic) value our node can take
        self.contains = contains    # list of items our node contains

然后我同样启动了我的背包求解器,但初始化了root = Node(0, 0, 0, 0.0, [])root.bound 的值可能是一个浮点数,这就是为什么我将它初始化为 0.0,而其他值(至少在我的问题中)都是整数。到目前为止,该节点不包含任何内容,因此我从一个空列表开始。我遵循了与您的代码类似的大纲,除了我将绑定存储在每个节点中(不确定这是必要的),并使用以下方法更新了 contains 列表:

u.contains = v.contains[:]    # copies the items in the list, not the list location
# Initialize u as Node(uLevel, uProfit, uWeight, 0.0, uContains)
u.contains.append(uLevel)    # add the current item index to the list

请注意,我只更新了“取物”节点中的contains 列表。这是主循环中的第一个初始化,位于第一个 if bound &gt; maxProfit: 语句之前。当您更新maxProfit 的值时,我在此之前更新了if: 语句中的contains 列表:

if u.weight <= knapsackSize and u.value > maxProfit:
    maxProfit = u.profit
    bestList = u.contains

这将存储您要带到bestList 的项目的索引。我还在v = queue.get() 之后的主循环中添加了条件if v.bound &gt; maxProfit and v.level &lt; items-1,这样我就不会在到达最后一项后继续前进,也不会循环遍历不值得探索的分支。

另外,如果你想得到一个二进制列表输出显示哪些项目是按索引选择的,你可以使用:

taken = [0]*numItems
for item in bestList:
    taken[item] = 1

print str(taken)

我的代码中还有一些其他的差异,但这应该可以让您得到您选择的项目列表。

【讨论】:

  • 这个“取物”分支到底在哪里?在我看来,“采用项目分支”是第一个运行 if bound &gt; maxProfit: 的 if 语句,但是在那里放置不会返回正确的索引。至少在我尝试过的地方。还有uContains 应该是u.contains
  • “获取项目”分支(我想节点是一个更好的词)是第一个 if bound &gt; maxProfit: 语句之前的代码。当我们更新 maxProfit 值时,包含列表在之前的语句中更新。我已经更新了我的答案以反映这一点。我还更正了 u.contains 变量名的问题,并将 value 更改为 profit 以与 OP 代码更加一致。
  • 这太棒了。我希望你的回答被接受。另外,我在 Node 类中编写了一个不涉及绑定参数的例程。简单地传递节点本身并提取节点的级别就足以让例程确定边界。
【解决方案2】:

我一直在考虑这个问题。显然,您必须在 Node 类中添加一些方法,这些方法将分配 node_path 并将当前级别添加到它。当您的 node_weight 小于容量并且它的值大于 max_profit 时,您在循环中调用您的方法并将 path_list 分配给您的 optimization_item_list,即您分配 maxProfit 的位置。可以找到java实现here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-04
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多