你有n1个大小为s1的项目,n2个大小为s2的项目,以及n3个大小为s3的项目。您希望将所有这些物品装入每个容量为C的容器中,以便最大限度地减少使用的垃圾箱总数。
我们如何使用最少数量的垃圾箱来实现解决方案?贪婪不一定有效。
答案 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)
是最低数量。需要分别填充i
,j
和k
件s1
,s2
,s3
的物品的箱子。
注意: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
其中x
,y
或z
中的至少一个必须大于0
,并且x
,y
或{{}之一{1}}必须分别小于z
,i
或j
。
运行时间: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).