#python #permutation
Вопрос:
У меня есть элемент А весом 1, а элемент В весом 2. Мне нужно найти возможные перестановки A и B, которые в сумме составляют определенную сумму.
Например, когда желаемая сумма равна 4, я хотел бы получить следующее:
[A, A, A, A]
[B, B]
[B, A, A]
[A, B, A]
[A, A, B]
Как лучше всего сделать что-то подобное? Сначала я попытался применить грубую силу, используя itertools.перестановки и проверяя суммы вручную (очень неэффективно, но я не был уверен, куда еще идти), но для больших чисел это было невозможно. Я хотел бы знать, как это сделать без импорта itertools или другой библиотеки, если это возможно?
Комментарии:
1. Это звучит так, как будто вы решаете проблему с рюкзаком. Я предлагаю прочитать о существующих решениях и посмотреть, можно ли их применить к вашей проблеме.
2. Спасибо! Похоже, это то, что я ищу. Я полагал, что решение уже существует, но я не мог подобрать правильные слова, чтобы найти его.
Ответ №1:
Это не перестановка, которую вы ищете, а комбинация. Перестановка — это перетасовка конечного набора элементов без повторений, в то время как комбинация-это каждое из n
полей, предполагающее один из m
элементов, который в python обозначается itertools.computations_with_replacement
как . В терминах кодекса:
import itertools
from functools import reduce
elements = {"A": 1, "B": 2, "C": 1}
sum_restriction = lambda x: sum(elements[i] for i in x)==4
max_els = 4 // min(elements.values()) 1
res = reduce(lambda x,y:x y,[list(filter(sum_restriction, itertools.combinations_with_replacement(elements.keys(), i))) for i in range(max_els 1)])
Для моего примера возвращаются:
>>> res
[('B', 'B'), ('A', 'A', 'B'), ('A', 'B', 'C'), ('B', 'C', 'C'), ('A', 'A', 'A', 'A'), ('A', 'A', 'A', 'C'), ('A', 'A', 'C', 'C'), ('A', 'C', 'C', 'C'), ('C', 'C', 'C', 'C')]
Ответ №2:
from itertools import permutations, chain
def get_permutations_count_to_n(item_dict, n, max_items=4):
""" For a given dict with items as keys and weights as values, return a set of permutations that have a combined weight of N
:param item_dict: dictionary with items as keys and their weight as value
:param n: integer that should be the combined weight of permutated items
:param max_items: the maximum number of items that may occur in a permutation """
item_list = list(items.keys()) * max_items
combs = [list(permutations(item_list, i)) for i in range(1, max_items 1)]
filtered_combs = [comb for comb in chain.from_iterable(combs) if sum(item_dict[x] for x in comb) == n]
return set(filtered_combs)
items = {'A': 1, 'B': 2}
get_permutations_count_to_n(items, n=4)
>>> {('B', 'A', 'A'), ('B', 'B'), ('A', 'A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'B', 'A')}