我们知道这些值是非零的,并且从左到右单调增长。
一个想法是枚举可能的总和(任何顺序,从左到右都可以),然后枚举该值左侧的子集,因为右侧的值不可能参与(他们也会求和)大的)。我们不必实例化集合;正如我们考虑每个值一样,看看 if 如何影响总和。它可能太大(忽略该值,不能在集合中),正好(它在集合中的最后一个成员),或者太小,此时它可能在集合中,也可能不在集合中。
【这个问题让我第一次玩Python。乐趣。]
这是Python代码;根据 Cprofile.run,这在我的 P8700 2.54Ghz 笔记本电脑上需要 0.00772 秒。
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。(匹配另一张海报的结果。)
编辑:ways_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 秒才能运行 :-} 相同的答案。