用python实现了算法,Macr1408翻译了代码,感谢算法的原作者Christian Blanquera。
from functools import reduce
from itertools import product
def combination(dim: list) -> list:
"""Calculate all possible sum permutations for a given list
of numbers.
Args:
dim (list): A list of numbers
Returns:
list: All possible sum permutations
"""
combination = []
total = pow(2, len(dim))
for i in range(total):
set_v = []
for j in range(total):
if (pow(2, j) & i):
set_v.append(dim[j])
if len(set_v) == 0 or sum(set_v) in combination:
continue
combination.append(sum(set_v))
return sorted(combination)
# dimensions => [(w1, h1, l1), (w2, h2, l2), ...]
def calculate_volumetric_total(dimensions: list[tuple[float, float, float]]) -> tuple:
"""Calculate the volumetric dimensions of the box needed to store products
with sizes stored as tuples of (width, height, length). Based on the following
algorithm:
1. Find total Volume (w*h*d)[+(w*h*d)..]
2. Collect all possible width height and depth values, sort each from lowest to highest
3. Find all possible sum permutations for width, then for height, then for width
3a. Example: sum permutations for width ranges 1,2,3 would be 1, 2, 3, 4, 5, 6
3b. we need this because in no way could the final value for width be 1.5 for example based on the example (3a.)
4. Find all possible combinations of Width, Height and Depth based on the permutations calculated on (3.)
5. Store all combinations where the total volume is equal or greater than the total Volume from (1.)
5a. This is because it is not possible that the final volume could be less than the actual Volume (1.)
5b. For Volumes greater than (1.) it means that's dead space.
6. Sort all combinations from (5.) Ascending, the first result will be the most accurate Volume
7. It is possible that the most accurate volume still could have different dimensions
7a. Example: Volume 16 can be 2x2x4 or 4x4x1 or 2x1x8 or 16x1x1
7b. Find the sum of W+H+D for each and the smallest sum would be the even more accurate dimensions.
7c. Example from (7a.) 2+2+4 = 8, 4+4+1 = 9, 2+1+8 = 11, 16+1+1 = 18 .... So our script would choose 2 x 2 x 4
Args:
dimensions (list[tuple[float, float, float]]): A list of all products/boxes
to store together in the form width, height, length.
Returns:
tuple: A tuple of width, height, length values representing the box needed to
store all the provided dimensions in.
"""
# 1
total_volume = sum([reduce(lambda x, y: x*y, t) for t in dimensions])
# 2, sorting happens when combining values
all_widths = [t[0] for t in dimensions]
all_heights = [t[1] for t in dimensions]
all_lengths = [t[2] for t in dimensions]
# 3
width_combination = combination(all_widths)
height_combination = combination(all_heights)
length_combination = combination(all_lengths)
# 4
vals = {}
for perm in product(width_combination, height_combination, length_combination):
# 5
volume = reduce(lambda x, y: x*y, perm)
if volume >= total_volume:
vals[sum(perm)] = perm
# 6
return vals[sorted(vals.keys())[0]]