在实施与经典 0-1 背包类似情况的解决方案时重复项目
Posted
技术标签:
【中文标题】在实施与经典 0-1 背包类似情况的解决方案时重复项目【英文标题】:Repeating items when implementing a solution for a similar situation to the classic 0-1 knapsack 【发布时间】:2017-04-10 16:44:15 【问题描述】:这个问题在很大程度上与经典的 0-1 背包问题相同,但有一些小的规则更改和一个大型数据集可供使用。
数据集(产品 ID、价格、长度、宽度、高度、重量): (20,000 行)
问题:
一家公司即将交付第 100 万份订单。营销团队决定为下订单的客户提供奖品,以表示感谢。奖品是:幸运客户获得一个送货手提袋和1小时在仓库。利用这一小时将您想要的任何产品装满手提包,然后免费带回家。
规则:
每项 1 个
组合体积
物品必须单独放入(尺寸应能放入手提包,例如 45 * 45 * 1 不适合)
组合产品的价值最大化
尽量减少抽签的重量
解决方案(使用动态规划):
from functools import reduce
# The main solver function
def Solver(myItems, myCapacity):
dp = myCapacity: (0, (), 0)
getKeys = dp.keys
for i in range(len(myItems)):
itemID, itemValue, itemVolume, itemWeight = myItems[i]
for oldVolume in list(getKeys()):
newVolume = oldVolume - itemVolume
if newVolume >= 0:
myValue, ListOfItems, myWeight = dp[oldVolume]
node = (myValue + itemValue, ListOfItems + (itemID,), myWeight + itemWeight)
if newVolume not in dp:
dp[newVolume] = node
else:
currentValue, loi, currentWeight = dp[newVolume]
if currentValue < node[0] or (currentValue == node[0] and node[-1] < currentWeight):
dp[newVolume] = node
return max(dp.values())
# Generate the product of all elements within a given list
def List_Multiply(myList):
return reduce(lambda x, y: x * y, myList)
toteDims = [30, 35, 45]
totalVolume = List_Multiply(toteDims)
productsList = []
with open('products.csv', 'r') as myFile:
for myLine in myFile:
myData = [int(x) for x in myLine.strip().split(',')]
itemDims = [myDim for myDim, maxDim in zip(sorted(myData[2:5]), toteDims) if myDim <= maxDim]
if len(itemDims) == 3:
productsList.append((myData[0], myData[1], List_Multiply(myData[2:5]), myData[5]))
print(Solver(productsList, totalVolume))
问题:
输出给出重复项
IE。 (14018, (26, 40, 62, 64, 121, 121, 121, 152, 152), 13869)
我怎样才能纠正这个问题,让它只选择每个项目中的一项?
【问题讨论】:
【参考方案1】:您的代码可能会产生带有重复项的答案的原因似乎是,在内部循环中,当您迭代到目前为止所有生成的卷时,代码可能已经替换了之前现有卷值的解决方案我们到了。
例如如果您的productsList
包含以下内容
productsList = [
# id, value, volume, weight
[1, 1, 2, 1],
[2, 1, 3, 2],
[3, 3, 5, 1]
]
和
totalVolume = 10
那么当你到达第三个项目时,dp.keys()
将包含:
10, 8, 7, 5
不保证迭代的顺序,但为了这个例子,我们假设它如上所示。然后dp[5]
将被包含项目#3 的新解决方案替换,在迭代的后期,我们将使用它作为新的、甚至更好的解决方案的基础(除了现在有重复项目)。
为了克服上述问题,您可以在迭代之前对键进行排序(按升序,这是默认值),例如for oldVolume in sorted(getKeys())
。假设所有项目都有一个非负数,这应该保证我们在迭代之前永远不会替换 dp
中的解决方案。
我在上面看到的另一个可能的问题是我们最终使用max(dp.values())
获得最佳解决方案的方式。在问题陈述中,它说我们希望在平局的情况下最小化权重。如果我没看错的话,元组的元素依次是 value、list of items、weight,所以下面我们' 与价值并列,但后一种选择会更可取,因为它的重量更小......但是max
返回第一个:
>>> max([(4, (2, 3), 3), (4, (1, 3), 2)])
(4, (2, 3), 3)
可以将排序键指定为max
,这样可能会起作用:
>>> max([(4, (2, 3), 3), (4, (1, 3), 2)], key=lambda x: (x[0], -x[-1]))
(4, (1, 3), 2)
【讨论】:
for oldVolume in sorted(getKeys()) 是我需要的!以上是关于在实施与经典 0-1 背包类似情况的解决方案时重复项目的主要内容,如果未能解决你的问题,请参考以下文章