就像@AlistairIsrael 说的那样,这是装箱问题,解决起来并不容易。
但是,以下是解决此问题的一种方法。
如果我们通过所有方式组合来包装物品并尝试找到最低成本,那么我们就有了解决方案。请注意,此解决方案是一种蛮力解决方案,因此会随着项目数量的增长而迅速放缓。
寻找所有可能的方式将货物分成不同的箱子;我们可以使用这个答案中的算法:
用于查找从 Python 到 Ruby 的集合的所有分区的翻译函数
接下来,我们遍历所有不同的组合并搜索最小成本。然后解决方案的工作方式如下:
> optimize_shipping([0.01, 0.01, 0.01, 0.01, 0.12])
Shipping type: courier
Total price : $10
Packaging : [[0.12], [0.01, 0.01, 0.01, 0.01]]
> optimize_shipping([0.01, 0.01, 0.12, 0.15, 0.12])
Shipping type: courier
Total price : $15
Packaging : [[0.01, 0.12], [0.15], [0.01, 0.12]]
> optimize_shipping([0.09, 0.09, 0.01, 0.12, 0.15, 0.12])
Shipping type: courier
Total price : $25
Packaging : [[0.12], [0.15], [0.12], [0.09, 0.01], [0.09]]
> optimize_shipping([0.01, 0.01, 0.01, 0.30])
Shipping type: freight
编码:
COURIER_LIMIT = 0.15
COURIER_PRICE = 5
class Array
def sum
inject(:+)
end
def partitions
yield [] if self.empty?
(0 ... 2 ** self.size / 2).each do |i|
parts = [[], []]
self.each do |item|
parts[i & 1] << item
i >>= 1
end
parts[1].partitions do |b|
result = [parts[0]] + b
result = result.reject do |e|
e.empty?
end
yield result
end
end
end
end
def optimize_shipping(boxes)
if boxes.any? { |b| b > COURIER_LIMIT }
puts "Shipping type: freight"
return
end
# Try and find the cheapest most optimal combination of packaging
smallest_box = 9999
cheapest_price = 9999
cheapest_combination = []
# Go through all paritions and find the optimal distribution
boxes.partitions { |partition|
# Add up sizes per box
sizes = partition.map(&:sum)
# Check if any box got too big for courier, and skip if so
next if sizes.any? { |s| s > COURIER_LIMIT }
# Calculate total price for this combination
total_price = partition.length * COURIER_PRICE
if total_price <= cheapest_price
# Naive algo to try and find best average distriution of items
next if total_price == cheapest_price && sizes.min < smallest_box
# Save this new optimized shipment
smallest_box = sizes.min
cheapest_price = total_price
cheapest_combination = partition
end
}
puts "Shipping type: courier"
puts "Total price : $#{cheapest_price}"
puts "Packaging : #{cheapest_combination.inspect}"
end