【发布时间】:2016-10-24 16:31:15
【问题描述】:
我在一次在线编码挑战中得到了这个问题。
给定一个长度和宽度为 (l, h) 的盒子列表,输出包含所有盒子所需的最小堆叠数,假设您可以将一个盒子堆叠在另一个盒子的顶部,如果它的长度和宽度小于其他盒子的。
我不知道如何提出多项式时间解决方案。我已经构建了一个蛮力解决方案,它递归地创建所有可能的堆栈排列(从 N 个堆栈开始。然后对于每个堆栈,尝试将它放在另一个堆栈的顶部。然后在给定新堆栈排列的情况下递归生成所有堆栈可能性。),然后返回所需的最少堆栈数。
我已经通过一些优化加快了速度:
- 如果您可以将盒子 A 堆叠在盒子 B 和盒子 C 的顶部,并且可以将盒子 B 堆叠在盒子 C 的顶部,那么请不要考虑将盒子 A 堆叠在盒子 C 上。
- 记住堆栈排列,仅考虑堆栈的底层和顶层
这是此解决方案的 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 个盒子问题。我很确定这是指数时间。 (因为堆栈排列的数量是指数级的)。
我很确定有一个多项式时间解,但我不知道它是什么。问题之一是记忆取决于当前的堆栈安排,这意味着您必须进行更多计算。
【问题讨论】:
-
把它变成图问题。
-
附带说明:如果您的代码按预期工作并希望使其变得更好,请尝试将其发布在此处:codereview.stackexchange.com
-
允许旋转盒子吗?
-
这看起来像一个类似的问题:stackoverflow.com/questions/21712133