Мы знаем, что значения ненулевые и растут монотонно слева направо.
Идея состоит в том, чтобы перечислить возможные суммы (любой порядок, слева направо в порядке), а затем перечислить подмножества вслева от этого значения , потому что значения справа не могут участвовать (они могут сделать сумму слишком большой).Нам не нужно создавать экземпляр набора;так же, как мы рассматриваем каждое значение, посмотрим, как если влияет на сумму.Он может быть либо слишком большим (просто игнорировать это значение, не может быть в наборе), либо правильным (его последний член в наборе), либо слишком маленьким, и в этот момент он может или не может быть в наборе.
[Эта проблема заставила меня играть с Python впервые.Fun.]
Вот код Python;в соответствии с Cprofile.run это занимает 0,00772 секунды на моем ноутбуке P8700 2,54 ГГц.
values = [3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61, 70, 73, 78, 81, 92, 95, 97, 99]
def count():
# sort(values) # force strictly increasing order
last_value=-1
duplicates=0
totalsets=0
for sum_value in values: # enumerate sum values
if last_value==sum_value: duplicates+=1
last_value=sum_value
totalsets+=ways_to_sum(sum_value,0) # faster, uses monotonicity of values
return totalsets-len(values)+duplicates
def ways_to_sum(sum,member_index):
value=values[member_index]
if sum<value:
return 0
if sum>value:
return ways_to_sum(sum-value,member_index+1)+ways_to_sum(sum,member_index+1)
return 1
Полученный счетчик равен 179. (Соответствует результату другого автора).
РЕДАКТИРОВАТЬ: way_to_sumможет быть частично реализован с использованием цикла хвостовой рекурсии:
def ways_to_sum(sum,member_index):
c=0
while True:
value=values[member_index]
if sum<value: return c
if sum==value: return c+1
member_index+=1
c+=ways_to_sum(sum-value,member_index)
Это займет 0,005804 секунды для запуска: -} Тот же ответ.