Мы можем немного изменить рецепт powerset
из документации itertools , чтобы не использовать явный цикл:
from itertools import chain, combinations
def powerset(iterable):
"powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(map(lambda r: combinations(s, r), range(len(s)+1)))
Для каждой комбинации багажа мы можем отфильтровать всете, которые превышают максимальный вес, затем берут тот, у которого больше всего предметов:
def calc_max_baggage(weights, W):
weights = powerset(weights)
filtered = filter(lambda items: sum(items) <= W, weights)
filtered = chain(filtered, ((),))
return max(filtered, key=len)
filtered = chain(filtered, ((),))
- это так, если W
отрицательно, мы не возвращаем мешки в любом случае, даже если технически сумма их весовбольше W
.
Это вернет фактический набор элементов, а не его длину, но вы можете легко преобразовать его.
>>> calc_max_baggage([4, 2, 3, 1], 5)
(4, 1)
>>> calc_max_baggage ([1, 1, 1], 5)
(1, 1, 1)
>>> calc_max_baggage([5], 0)
()
Если вам нужен рекурсивный компонент,вы можете определить powerset
рекурсивно, хотя это заметно менее эффективно
def powerset(seq):
if not seq:
return ((),)
else:
head, *tail = seq
tail_pow = powerset(tail)
with_head = tuple(map(lambda t: (head,) + t, tail_pow))
return with_head + tail_pow