Bin Packing动态编程问题

时间:2011-04-19 17:29:29

标签: algorithm

你有n1个大小为s1的项目,n2个大小为s2的项目,以及n3个大小为s3的项目。您希望将所有这些物品装入每个容量为C的容器中,以便最大限度地减少使用的垃圾箱总数。

我们如何使用最少数量的垃圾箱来实现解决方案?贪婪不一定有效。

8 个答案:

答案 0 :(得分:6)

这不是一个愚蠢的问题,IMO。

一般认为Bin填料是NP-Complete。

但是你的情况是,具有固定数量的对象权重的Bin打包是一个有趣的变体。

以下论文声称有一个多项式时间算法,当你允许3个不同的大小时,它会带有1个最优:http://linkinghub.elsevier.com/retrieve/pii/S0377221706004310。 (警告:我只是抽象的)。

所以我猜这个版本也是NP-Hard,而Greedy算法可能不会起作用。不太确定动态编程(bin打包是NP-Complete)。

希望有所帮助。

答案 1 :(得分:2)

它效率不高,但您可以使用简单的动态编程算法在多项式时间中解决此多项式的次数取决于你拥有的不同大小的数量。

我已经包含了一个实现,对于3种不同的大小,O(n1 * n2 * n3 * (C/s2) * (C/s3) * ((n1*s1 + n2*s2 + n3*s3)/C))具有非常糟糕的常量。 (这个数字来自于这样一个事实,即我们可用的不同模式的数量是O(n1 * n2 * n3),并且每个我们生成O((C/s2) * (C/s3))可能的下一个垃圾箱,我们必须使用它们大小为O((n1*s1 + n2*s2 + n3*s3)/C))的一组箱。许多例行优化可以大大加快这个程序。)

#! /usr/bin/python
import heapq

def min_bins(bin_size, sizes, counts):
    available = zip(sizes, counts)
    available.sort(reverse=True)
    seen = set([])
    upcoming = [(0, available, [])]
    while 0 < len(upcoming):
        (n, available, bins) = heapq.heappop(upcoming)
        for (bin, left) in bin_packing_and_left(bin_size, available):
            new_bins = bins + [bin]
            if 0 == len(left):
                return new_bins
            elif left not in seen:
                heapq.heappush(upcoming, (n+1, left, new_bins))
                seen.add(left)

def bin_packing_and_left(bin_size, available, top=True):
    if 0 == len(available):
        yield ((), ())
    else:
        (size, count) = available[0]
        available = available[1:]
        for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
            can_use = (bin_size - used) / size
            if count <= can_use:
                yield(((size, count),) + bin, left)
            elif 0 < can_use:
                yield(((size, can_use),) + bin,
                      ((size, count - can_use),) + left)
            else:
                yield(bin, ((size, count),) + left)

def bin_packing_and_left_size(bin_size, available):
    if 0 == len(available):
        yield ((), (), 0)
    else:
        (size, count) = available[0]
        available = available[1:]
        for (bin, left, used) in bin_packing_and_left_size(bin_size, available):
            for i in range(1 + min(count, (bin_size - used) / size)):
                if count == i:
                    yield(((size, count),) + bin, left, used + size * count)
                elif 0 < i:
                    yield(((size, i),) + bin,
                          ((size, count - i),) + left,
                          used + size * i)
                else:
                    yield(bin, ((size, count),) + left, used)

answer = min_bins(23, (2, 3, 5), (20, 30, 40))
print len(answer)
print answer

答案 2 :(得分:2)

可以在O(n1*n2*n3) ...

中完成

可以说,f(i,j,k)是最低数量。需要分别填充ijks1s2s3的物品的箱子。

注意:C是垃圾箱的容量

f(i,j,k)将包含两种信息:

a)(The min no. of bins that are currently required) - 1。说该属性为B1

b)可用于进一步归档的最后一个bin的当前大小..说该属性为B2 ..其中0 < B2 <= C

因此,重现将是:

f(i,j,k)([B1],[B2]) =
  min 
 { 
    f(i-1, j, k)( [B1] + [B2 + S1]/(C+1) , [B2 + S1] <=C ? [B2 + S1] : [B2 + S1 - C]) ,
    f(i, j-1, k)( [B1] + [B2 + S2]/(C+1) , [B2 + S2] <=C ? [B2 + S2] : [B2 + S2 - C]) ,
    f(i, j, k-1)( [B1] + [B2 + S3]/(C+1) , [B2 + S3] <=C ? [B2 + S3] : [B2 + S3 - C])
 }

最低编号需要的箱子:1 + f(n1, n2, n3)[B1]

答案 3 :(得分:0)

如果你可以将问题减少到1d bin-packing,你想使用这里使用的贪婪算法:http://www.developerfusion.com/article/5540/bin-packing

答案 4 :(得分:0)

如果尺寸是一维的,或者它可以减小到一维值,则可以将其解决为多袋背包问题(MKP),其中物品的重量等于其益处。如果将#bin设置为可用项目数的上限(一目了然,如果您的实例不是很高,此值可以是#items),您可以使用分支和绑定最佳地解决此问题。其他优化算法。如果你能承认非最优解,那就有一些可行的贪婪算法。

然而,由于我从未深入研究过这个问题,所以我不太确定。然而,有一本名​​为“背包问题”的书,介绍了配方和算法,包括装箱问题。不难在互联网上找到它作为PDF。

希望这有帮助。祝你好运。

答案 5 :(得分:0)

假设包装优良的最小数量为B = ceiling( sum(n(i)*s(i) for i in 1..3) / C )

使用所谓的first_fit,但实际上是bad_fit,交换来自here以查看这些项是否适合B箱。如果没有,增加B并重复直到它们适合。

答案 6 :(得分:0)

这是这个DP算法的草图。

递归关系:我们递归B(i, j, k),即包装大小为s1的项目,大小为s2的j项目和大小为s3的k项目所需的容量C的最小容器数。关系是:

B(i, j, k) = min {B (x,y,z) , B(i-x, j-y, k-z)} 
where 0<=x<=i; 
0<=y<=j; 
0<=z<=k

其中xyz中的至少一个必须大于0,并且xy或{{}之一{1}}必须分别小于zij

运行时间:B的大小为O(n3),计算B的每个元素需要时间O(n3),总时间为O(n6)。

答案 7 :(得分:0)

如果我们能找到一个垃圾箱的最佳解决方案,这意味着我可以在一个垃圾箱中放入最大数量的元素,这将导致回答。

让我们假设大小为S1的元素,大小为S2的b元素,大小为S3的c元素是我可以放在一个bin中的元素的最大数量。所以我可以装入一个箱子的最大尺寸是K = a * S1 + b * S2 + c * S3。所以答案是(n1 * S1 + n2 * s2 + n3 * s3)/ K +(n1 * S1 + n2 * s2 + n3 * s3)%K no of bin。

查找K比标准背包问题更容易。如果我假设所有最优值直到i存在1&lt; = i&lt; = C.那么i + 1的最佳值可以递归写入

M(i+1) = max(M(i),M(i-S1)+S1,M(i-S2)+S2,M(i-S3)+S3).