【问题标题】:Almost solved 0/1 Bidimensional Knapsack in python几乎解决了python中的0/1二维背包
【发布时间】:2016-02-19 18:16:48
【问题描述】:

我试图从这个列表中选择最多 10 个项目以获得更高的利润。

  Item name | Item "Weight" | Item "Profit"

         [A, 1084, 424],
         [B, 1143, 391],
         [C, 1205, 351],
         [D, 1088, 328],
         [E, 5, 21],
         [F, 996, 241],
         [G, 13, 23],
         [H, 2, 9],
         [I, 5, 13],
         [J, 14, 21],
         [K, 11, 18],
         [L, 4, 12],
         [M, 121, 59],
         ...
    Total length: 249

我发现我的问题可以定义为0/1 Bidimensional Knapsack problem。重量将是第一个维度,10 项限制将是第二个维度。所以我用python尝试了不同的解决方案来优化选择。

搜索不同的来源后,我无法找到针对我的具体问题的 python 解决方案:

  • 定义的重量限制(介于 100-10.000 之间)
  • 每个项目只能选择一次
  • 总共只能选择 10 项
  • 最大化“利润”!

最后我找到了this java 解决方案,我试图翻译,但在某处出错,该功能几乎可以正常工作,但无法找到正确的解决方案。我花了几天时间试图找出代码失败的地方,但这有点令人困惑。

from collections import namedtuple

Bounty = namedtuple('Bounty', 'name value size volume')

sack =   Bounty('sack', value=0, size=800, volume=10)

items = results #A big list as mentioned above

dynNoRep = [[[0 for k in xrange(sack.volume+1)] for j in xrange(sack.size+1)] for i in xrange(
            len(items) + 1)]

for i,item in enumerate(items):
    for j in range(sack.size):
        for h in range(sack.volume):
            if item.size > j:

                #pdb.set_trace()
                dynNoRep[i][j][h] = dynNoRep[i-1][j][h]
            elif item.volume > h:
                dynNoRep[i][j][h] = dynNoRep[i-1][j][h]
            else:
                dynNoRep[i][j][h] = max(
        dynNoRep[i-1][j][h], dynNoRep[i-1][j - items[i-1].size][h - items[i-1].volume] + items[i-1].value)

for i,item in enumerate(items):
    for j in range(sack.size):
        dynNoRep[i][j][sack.volume] = dynNoRep[i][j][sack.volume-1]

j = sack.size
h = sack.volume
finalSize = 0
finalValue = 0
finalVolume = 0

for i in range(len(items)-1, -1, -1):
    #pdb.set_trace()
    if dynNoRep[i][j][h] != dynNoRep[i-1][j][h]:
        print"Value {} | Size {} | Volume {}".format(str(items[i-1].value), str(items[i-1].size), str(items[i-1].volume))
        finalSize += items[i-1].size
        finalValue += items[i-1].value
        finalVolume += items[i-1].volume
        j -= items[i - 1].size
        h -= items[i - 1].volume


print('Final size {} / {}'.format(str(finalSize), str(sack.size)))
print('Final volume {} / {}'.format(str(finalVolume), str(sack.volume)))
print('Final value {}'.format(str(finalValue)))

这是输出,有时它显示更好的东西,但从来不是正确的解决方案:

Final size 0 / 800
Final volume 0 / 10
Final value 0

上下文:Windows 8.1 32 位。 Ipython 笔记本。 Python 2.

对使代码有效的任何建议?提前谢谢!

【问题讨论】:

    标签: python dynamic-programming knapsack-problem


    【解决方案1】:

    最后在 ipython 中使用 Cython 更容易,“翻译”一个 C++ 算法found here

    这是所需的导入:

    %load_ext Cython
    

    请务必先安装 cython 扩展。

    这是上一个链接中“Cython”版本的代码:

    %%cython
    
    from libc.string cimport memset
    
    cdef int noOfItems, maxWeight, maxItems
    cdef int items[100]
    cdef int value[100]
    cdef int dp[100][1000][100]
    
    cdef int solve(int idx, int currentWeight, int itemsLeft, noOfItems):
        if idx == noOfItems or itemsLeft == 0:
            return 0
        if dp[idx][currentWeight][itemsLeft] != -1:
            return dp[idx][currentWeight][itemsLeft]
        cdef int v1 = 0
        cdef int v2 = 0
    
        if currentWeight >= items[idx]:
            v1 = solve(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems) + value[idx]
            v2 = solve(idx+1, currentWeight, itemsLeft, noOfItems)
    
        dp[idx][currentWeight][itemsLeft] = max(v1, v2)
    
        return dp[idx][currentWeight][itemsLeft]
    
    cdef void printer(int idx, int currentWeight, int itemsLeft, noOfItems):
        if idx == noOfItems or itemsLeft == 0:
            return
        cdef int v1 = 0
        cdef int v2 = 0
        if currentWeight >= items[idx]:
            v1 = solve(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems) + value[idx]
            v2 = solve(idx+1, currentWeight, itemsLeft, noOfItems)
        if v1 >= v2:
            print(items[idx], value[idx])
            printer(idx+1, currentWeight-items[idx], itemsLeft-1, noOfItems)
            return
        else:
            printer(idx+1, currentWeight, itemsLeft, noOfItems)
            return
    
    cdef knapsack(lenitems, maxWeight, maxItems):
    
        noOfItems = lenitems
        maxWeight = 15
        maxItems = 3
        pairs =  [[4,6], [3,4], [5, 5], [7, 3], [7, 7]]
        for i in range(noOfItems):
            items[i] = pairs[i][0]
            value[i] = pairs[i][1]
            memset(dp, -1, sizeof(dp))
            print(solve(0, maxWeight, maxItems, noOfItems))
            print "Printing the elements in the knapsack"
            printer(0, maxWeight, maxItems, noOfItems)
    
    def pyknapsack(lenitems, maxWeight=15, maxItems=3):
        print 'Hao'
        knapsack(lenitems, maxWeight, maxItems)
    

    pyknapsack 函数是一个 python “包装器”,因此您可以在 python 中使用 C 函数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多