我在一个在线编码挑战中遇到了这个问题。
给定具有长度和宽度(l,h)的盒子列表,请输出容纳所有盒子所需的最小堆叠数量,如果您可以将一个盒子的长度和宽度小于另一个盒子的宽度,则可以将一个盒子堆叠在另一个盒子的顶部。
我不知道如何提出多项式时间解决方案。我构建了一个蛮力解决方案,该解决方案以递归方式创建所有可能的堆栈排列(从N个堆栈开始。然后对于每个堆栈,尝试将其放置在另一个堆栈之上。然后在给出新堆栈排列的情况下递归生成所有堆栈可能性。),然后返回所需的最小堆栈数。
我通过一些优化加快了速度:
这是此解决方案的python代码:
from time import time
def all_stacks(bottom, top, d={}):
memo_key = (tuple(bottom), tuple(top))
if memo_key in d:
# print "Using MEMO"
return d[memo_key]
res = len(bottom)
found = False
stack_possibilities = {}
# try to stack the smallest boxes in all the other boxes
for j, box1 in enumerate(bottom):
stack_possibilities[j] = []
for i, box2 in enumerate(top[j:]):
# box1 fits in box2
if fits(box2, box1):
stack_possibilities[j].append(i + j)
found = True
for fr, to_list in stack_possibilities.iteritems():
indices_to_keep = []
for box_ind in to_list:
keep = True
for box_ind_2 in to_list:
if fits(top[box_ind], top[box_ind_2]):
keep = False
if keep:
indices_to_keep.append(box_ind)
stack_possibilities[fr] = indices_to_keep
if found:
lens = []
for fr, to_list in stack_possibilities.iteritems():
# print fr
for to in to_list:
b = list(bottom)
t = list(top)
t[to] = t[fr]
del b[fr]
del t[fr]
lens.append(all_stacks(b, t, d))
res = min(lens)
d[memo_key] = res
return res
def stack_boxes_recursive(boxes):
boxes = sorted(boxes, key=lambda x: x[0] * x[1], reverse=False)
stacks = all_stacks(boxes, boxes)
return stacks
def fits(bigbox, smallbox):
b1 = smallbox[0] < bigbox[0]
b2 = smallbox[1] < bigbox[1]
return b1 and b2
def main():
n = int(raw_input())
boxes = []
for i in range(0,n):
l, w = raw_input().split()
boxes.append((long(l), long(w)))
start = time()
stacks = stack_boxes_recursive(boxes)
print time() - start
print stacks
if __name__ == '__main__':
main()
输入
17
9 15
64 20
26 46
30 51
74 76
53 20
66 92
90 71
31 93
75 59
24 39
99 40
13 56
95 50
3 82
43 68
2 50
输出:
33.7288980484
6
该算法可在几秒钟(1-3)内解决16盒问题,在约30秒内解决17盒问题。我很确定这是指数时间。 (由于堆栈排列的数量成倍增加)。
我很确定这里有多项式时间解,但是我不知道它是什么。问题之一是记忆化取决于当前的堆栈安排,这意味着您必须进行更多的计算。
最佳答案
让我们构建一个图形,其中每个框都有一个顶点,并且如果A可以堆叠在B的顶部,则从框A到框B的边都存在。该图是非循环的(因为“可以堆叠在顶部”是传递关系,并且盒装不能堆叠在其顶部)。
现在我们需要找到该图的最小路径覆盖。这是一个标准问题,可以通过以下方式解决:
A->B
边缘,在A
的左侧副本和B
的右侧副本之间都有一条边缘。 二部图为
O(n)
顶点和O(n^2)
边。例如,如果我们使用Kuhn算法查找匹配项,则总时间复杂度为O(n^3)
,其中n
是箱数。关于python - 将箱子有效地堆叠到最少数量的堆叠中?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40223257/