При столкновении с подобной проблемой часто бывает неплохо сделать шаг назад от вашего редактора/IDE и подумать о проблеме, вытащив простой случай на доске. Даже не делайте псевдокод, просто вытяните блок-схему того, как простой случай (например, a = 3
) для этой проблемы будет черепаха полностью вниз. Кроме того, сначала не волнуйтесь о дублированных комбинациях. Попробуйте найти решение, которое даст вам все необходимые комбинации, а затем улучшит ваше решение, чтобы не дать вам дубликатов. В этом случае, почему бы не посмотреть на управляемый случай a = 3
? Позвольте мне сделать для вас маленькую картинку.Зеленая галочка означает, что мы пришли к действительной комбинации, красный крест означает, что комбинация недействительна.
Как вы можете видеть, мы начинаем с тремя пустыми субкомбинациями, а затем построить три новых подкомбинации пути добавления номера к каждому из них. Мы хотим изучить все возможные пути, поэтому мы выбираем 1, 2 и 3 и получаем [1]
, [2]
и [3]
. Если сумма чисел в комбинации равна 3, мы нашли действительную комбинацию, поэтому мы можем остановиться, чтобы изучить этот путь. Если сумма чисел в комбинации превышает 3, комбинация недействительна, и мы также можем остановиться. Если это не так, мы просто продолжаем строить комбинации до тех пор, пока не получим какое-либо действительное или недействительное решение.
Поскольку ваш вопрос, похоже, прежде всего касается того, как выработать рекурсивное решение для таких проблем и меньше о конкретном синтаксисе, и вам просто удалось найти решение на C++, которое я собираюсь предоставить в Python (это почти выглядит как псевдокод, и это то, что он знает).
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in the combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
for number in range(1, a + 1): # try each number from 1 to a
if combosum + number <= a: # only proceed if we don't exceed a
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations c that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Давайте проверим код!
>>> combos = getcombs(3)
>>> for combo in combos: print(combo)
...
[1, 1, 1]
[1, 2]
[2, 1]
[3]
Это, кажется, работает хорошо, еще одно испытание для a = 5
:
>>> combos = getcombs(5)
>>> for combo in combos: print(combo)
...
[1, 1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 1]
[1, 1, 3]
[1, 2, 1, 1]
[1, 2, 2]
[1, 3, 1]
[1, 4]
[2, 1, 1, 1]
[2, 1, 2]
[2, 2, 1]
[2, 3]
[3, 1, 1]
[3, 2]
[4, 1]
[5]
Решение включает в себя все семь комбинаций мы искали, но код все еще производит дубликаты. Как вы могли заметить, нет необходимости брать число, меньшее, чем предыдущий выбранный номер, для создания всех комбинаций. Итак, добавим код, который только начинает строить extcombo
для чисел, которые не меньше последнего текущего числа в комбинации. Если комбинация пуста, мы просто устанавливаем предыдущий номер на 1.
def getcombs(a, combo = None):
# initialize combo on first call of the function
if combo == None:
combo = []
combosum = sum(combo) # sum of numbers in combo, note that sum([]) == 0
# simple case: we have a valid combination of numbers, i.e. combosum == a
if combosum == a:
yield combo # this simply gives us that combination, no recursion here!
# recursive case: the combination of numbers does not sum to a (yet)
else:
lastnumber = combo[-1] if combo else 1 # last number appended
for number in range(lastnumber, a + 1): # try each number between lastnumber and a
if combosum + number <= a:
extcombo = combo + [number] # append the number to the combo
# give me all valid combinations that can be built from extcombo
for c in getcombs(a, extcombo):
yield c
Еще раз протестируем код!
Представленное решение может быть не самым эффективным, но оно, однако, надеется, что оно побудит вас мыслить рекурсивно. Разбивайте проблему шаг за шагом, вытащите простой случай для небольших входов и разрешите одну проблему за раз.
Дополнительная проблема с решением находится в инструкции 'if (num <= 0)'. Это должно быть 'if (num == 0)', так как это фактический тест, который означает остановку алгоритма. Он будет работать с '<=', так как вызов обеспечивает, что 'num' никогда не будет ниже 0, но логически это неправильно и вводит в заблуждение. – SomeWittyUsername