在为类似情况实施解决方案时,重复项目为经典的0-1背包

时间:2017-04-10 16:44:15

标签: python python-3.x dynamic-programming

这个问题与经典的0-1背包问题大致相同,但是会有一些小的规则变化和大数据集。

数据集(产品ID,价格,长度,宽度,高度,重量): (20,000行)

enter image description here

问题

一家公司正在快速交付第100万笔订单。营销团队决定将作出该订单的客户作为赞赏的姿态。奖品是:幸运的顾客在仓库中获得一个交货手提包和1小时。用小时填充你想要的任何产品的手提包,然后免费带回家。

规则

  • 每个项目中的1个

  • 组合体积<手提袋容量(45 * 30 * 25 = 47250)

  • 物品必须单独放置(尺寸可以放入手提包中,例如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))

问题

输出正在重复项目 即。 (14018, (26, 40, 62, 64, 121, 121, 121, 152, 152), 13869)

如何纠正此问题,使其只选择每个项目中的一个?

1 个答案:

答案 0 :(得分:1)

看起来您的代码可能会产生重复项的答案的原因是,在内部循环中,当您到目前为止迭代所有生成的卷时,代码可能已经替换了现有卷值的解决方案我们到了那里。

E.g。如果您的sudo resize2fs /dev/xvda1包含以下内容

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 将被包含项目#3的新解决方案所取代,稍后在迭代中,我们将使用它作为新的,更好的解决方案的基础(现在除了重复项目)。

为了克服上述问题,您可以在迭代之前对其进行排序(按升序排列,这是默认值),如dp[5]。假设所有项目都具有非负数量,这应该保证我们在迭代它之前永远不会替换for oldVolume in sorted(getKeys())中的解决方案。

我在上面看到的另一个可能的问题是我们使用dp在最后获得最佳解决方案的方式。在问题陈述中,它表示我们希望在平局的情况下最小化重量。如果我正确读取代码,元组的元素按顺序是 value 项目列表 weight ,所以下面我们为价值而束缚,但后者的选择会更好,因为权重较小......但是max(dp.values())会返回第一个:

max

可以将排序键指定为>>> max([(4, (2, 3), 3), (4, (1, 3), 2)]) (4, (2, 3), 3) ,这样可能会起作用:

max