我的客户是一家生产不同块(不同尺寸)木地板的公司。他们的问题是,当有人在木地板上购买XXm²时,他们必须将其装箱。
此盒子最大可容纳220厘米。片段从30厘米开始,上升5厘米,直到完整的220厘米为止。
我要达到什么目的?箱子中不同部分和大小的最佳组合至少要有一个大块的底部,否则箱子会“刹车”。那是因为盒子需要坚固的底部才能处理上面的其他物件。
是的。让我们去看看代码吧!
客户输入作品,诸如此类:
[220, 170, 150, 145, 130, 125, 125, 115, 110, 110, 105, 95, 95, 90,
90, 90, 75, 70, 70, 60, 60, 50, 50, 50, 50, 50, 50, 40]
最好的输出之一是:
['220', '170,50', '150,70', '145,75', '130,90',
'125,95', '125,95', '115,105', '110,110', '90,90,40',
'70,50,50,50', '60,60,50,50',]
我正在尝试使用itertools:
from itertools import combinations
for i in range(1, 5): # Maximum 4 pieces
for comb in combinations(customer_input, i):
if sum(comb) <= 220 and sum(comb) >= 195:
print(comb)
第一张照片是:
(220,)
(170, 50)
(170, 50)
(170, 50)
(170, 50)
(170, 50)
(170, 50)
看起来好像正确,但是,它一次输出组合(170, 50)
。我认为,一种方法是在使用了一部分后停止尝试进行新的组合。
我该如何实现?
答案 0 :(得分:2)
这是一种做我认为您正在尝试的方法:
from collections import Counter
# Generate all combinations up to n elements without repetitions
# with sum up to max_sum
def combs(p, n, max_sum):
p = sorted(p, reverse=True)
return _combs_rec(p, n, max_sum, 0, [], 0)
def _combs_rec(p, n, max_sum, idx, current, current_sum):
if len(current) > 0:
yield current_sum, tuple(current)
prev = None
if n > 0:
for i in range(idx, len(p)):
if p[i] != prev and current_sum + p[i] <= max_sum:
current.append(p[i])
yield from _combs_rec(p, n - 1, max_sum, i + 1, current, current_sum + p[i])
current.pop()
prev = p[i]
# Input data
pieces = [220, 170, 150, 145, 130, 125, 125, 115, 110, 110, 105, 95, 95, 90,
90, 90, 75, 70, 70, 60, 60, 50, 50, 50, 50, 50, 50, 40]
max_group = 4
max_sum = 220
# Get maximum combinations
c = Counter(pieces)
while sum(c.values()) > 0:
next_sum, next_comb = max(combs(c.elements(), max_group, max_sum))
c.subtract(next_comb)
print(f'{next_comb} Sum: {next_sum}')
输出:
(220,) Sum: 220
(170, 50) Sum: 220
(150, 70) Sum: 220
(145, 75) Sum: 220
(130, 90) Sum: 220
(125, 95) Sum: 220
(125, 95) Sum: 220
(115, 105) Sum: 220
(110, 110) Sum: 220
(90, 90, 40) Sum: 220
(70, 50, 50, 50) Sum: 220
(60, 60, 50, 50) Sum: 220
请注意,这不一定能提供最佳解决方案。即使每次迭代都在进行蛮力搜索以寻求最佳组合,但它仍然是一个贪婪的算法。无法保证每次选择最佳组合都会使您获得总松弛度最小的组合组。为此,您将必须在该组片段的分区的全局空间内进行搜索。
答案 1 :(得分:0)
使用set
是避免重复的简单解决方案:
customer_input = [220, 170, 150, 145, 130, 125, 125, 115, 110, 110, 105, 95, 95, 90,
90, 90, 75, 70, 70, 60, 60, 50, 50, 50, 50, 50, 50, 40]
from itertools import combinations
combs = set()
for i in range(1, 5): # Maximum 4 pieces
for comb in combinations(customer_input, i):
if sum(comb) <= 220 and sum(comb) >= 195 and comb not in combs:
print(comb)
combs.add(comb)
# part of output:
# (220,)
# (170, 50)
# (170, 40)
# (150, 70)
# (150, 60)
# (150, 50)
# (145, 75)
答案 2 :(得分:0)
这不是代码答案,而是一种拓宽视野的想法。
这种问题可以称为优化问题,称为Knapsack problem。
解决背包问题的一种方法可能是使用动态编程(我链接的维基百科页面上有关于这一部分的内容)。关于如何进行类似编程的教程也很多。 例如,这里有一个freecodecamp tutorial用于动态解决背包问题;它不是在Python中,但重要的部分是了解如何解决此类问题。
我希望您可以从正确的方向开始,以获得最佳的代码解决方案。