使用分支定界算法我已经评估了给定项目集的最佳利润,但现在我想知道哪个项目包含在这个最优解决方案中。我正在评估最佳背包的利润值如下(改编自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
那么,如何才能获得构成最佳解决方案的项目,而不仅仅是利润?
答案 0 :(得分:3)
我使用您的代码作为起点。我将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 > maxProfit:
语句之前。在您更新contains
的值时,我在if:
语句中更新了maxProfit
列表:
if u.weight <= knapsackSize and u.value > maxProfit:
maxProfit = u.profit
bestList = u.contains
这会将您正在拍摄的项目的索引存储到bestList
。我还在if v.bound > maxProfit and v.level < items-1
之后的主循环中添加了条件v = queue.get()
,这样在我到达最后一个项目后我就不会继续进行,而且我不会遍历不值得探索的分支。
另外,如果您想获得一个二进制列表输出,显示哪些项目是通过索引选择的,您可以使用:
taken = [0]*numItems
for item in bestList:
taken[item] = 1
print str(taken)
我的代码中还有其他一些差异,但这可以让您获得所选的项目列表。
答案 1 :(得分:2)
我一直在考虑这个问题。显然,您必须在Node类中添加一些方法,这些方法将分配node_path并向其添加当前级别。您可以在循环内调用方法,并在node_weight小于容量并且其值大于max_profit(即分配maxProfit的位置)时将path_list分配给optimal_item_list。您可以找到java实现here