问题描述
我正在处理子集和问题的一个特别讨厌的变体。
请考虑以下示例。假设我们有几个仓库,其中某些物品的数量不同。例如:
- 伦敦-1个项目
- 利物浦-2个项目
- 纽卡斯尔-50个项目
- 曼彻斯特-70项
比方说,我们还有一个100件商品的交货订单,我们想创建所有可以满足该订单的组合,如下所示:
- 曼彻斯特(70)+纽卡斯尔(30)
- 纽卡斯尔(50)+曼彻斯特(50)
- 伦敦(1)+纽卡斯尔(50)+曼彻斯特(49)
- 伦敦(1)+曼彻斯特(70)+纽卡斯尔(29)
- 利物浦(2)+纽卡斯尔(50)+曼彻斯特(48)
- 利物浦(2)+曼彻斯特(70)+纽卡斯尔(28)
- 伦敦(1)+利物浦(2)+纽卡斯尔(50)+曼彻斯特(47)
- 伦敦(1)+利物浦(2)+曼彻斯特(70)+纽卡斯尔(27)
一些警告:
- 如果我们从两个仓库中提取全部库存,则顺序无关紧要。例如,伦敦(1)+利物浦(2)+纽卡斯尔(50)+曼彻斯特(47)等同于利物浦(2)+伦敦(1)+纽卡斯尔(50)+曼彻斯特(47),我们应该只返回一个变体(与哪个变体无关)
- 另一方面,如果我们只提取部分库存,则订单很重要。例如,伦敦(1)+利物浦(2)+纽卡斯尔(50)+曼彻斯特(47)不等同于利物浦(2)+伦敦(1)+曼彻斯特(70) + Newcastle(27),我们应该返回两个变体
- 仓库(和变体)的数量可能非常多,因此我无法为哈希集分配任何额外的内存
有了这样的警告,我什至不确定这是否是子集和问题的变体。
在此先感谢您的帮助。
解决方法
在假设卡车在任何地方都尽可能多地捡起卡车(因此唯一可能的部分负荷是在它最后一次拜访的地方)下,以下代码应该起作用:
def loads (load_size,warehouse_capacity):
warehouses = list(warehouse_capacity.keys())
subset_sums = {0: None}
for i in range(len(warehouses)):
capacity = warehouse_capacity[warehouses[i]]
for prev_sum in list(subset_sums.keys()):
if prev_sum + capacity <= load_size:
if prev_sum + capacity not in subset_sums:
subset_sums[prev_sum + capacity] = [i]
else:
subset_sums[prev_sum + capacity].append(i)
def comb_sums (target,partial_comb):
if target == 0:
yield partial_comb
else:
for i in subset_sums[target]:
if i not in partial_comb:
capacity = warehouse_capacity[warehouses[i]]
partial_comb[i] = capacity
for comb in comb_sums(target - capacity,partial_comb):
yield comb
partial_comb.pop(i)
for target in subset_sums.keys():
if target == load_size:
for comb in comb_sums(load_size,{}):
yield dict([(warehouses[i],c) for i,c in comb.items()])
else:
for j in range(len(warehouses)):
if load_size < target + warehouse_capacity[warehouses[j]]:
for comb in comb_sums(target,{j: load_size-target}):
yield dict([(warehouses[i],c in comb.items()])
for comb in loads(100,{'London': 1,'Liverpool': 2,'Newcastle': 50,'Manchester': 70}):
print(comb)