这里有一个解决方案。思路是通过
n次循环计算得出可以获得的所有值的可能总和,计算不同可能总和的数量,并将大于阈值的总和相加。
接下来,我们可以通过将我们的值添加到之前的总和中生成
n+1次循环的所有可能总和。我们希望不同可能总和的数量不会增长太多,因为我们多次添加相同的值,并将所有大于阈值的总和进行重组。
from collections import Counter
def all_sums(values, threshold, previous_sums = None):
"""
values must be sorted
previous_sums is a Counter of previously obtained possible sums
Returns a Counter of all possible sums of values and the previous sums
"""
if not previous_sums:
previous_sums = Counter({0:1})
new = Counter()
for existing_sum, ex_sum_count in sorted(previous_sums.items()):
for index, val in enumerate(values):
total = existing_sum + val
if total < threshold:
new.update({total: ex_sum_count})
else:
values_left = len(values) - index
new.update({threshold: values_left * ex_sum_count})
break
return new
def count_sums(values, threshold, repeat):
"""
values must be sorted!
Recursively calculates the possible sums of 'repeat' values,
counting together all values over 'threshold'
"""
if repeat == 1:
return all_sums(values, threshold, previous_sums=None)
else:
return all_sums(values, threshold, previous_sums=count_sums(values, threshold, repeat=repeat-1))
让我们以您的例子来尝试一下:
loops = 10
results = [4, 2.75, 2.75, 1.5, 1.5, 1.5, 0]
threshold = loops * 2
values = sorted(results)
sums = count_sums(values, threshold, repeat=loops)
print(sums)
number_of_sums = len(results) ** loops
good = sums[threshold]
bad = number_of_sums - good
我测试了一下,在我的相对陈旧的机器上需要大约9毫秒。另外还有一些数据:10个不同的值,20次循环:
loops = 20
results = [4, 2.75, 2.45, 1.5, 1.3, 0.73, 0.12, 1.4, 1.5, 0]
threshold = loops * 2
values = sorted(results)
sums = count_sums(values, threshold, repeat=loops)
number_of_sums = len(results) ** loops
good = sums[threshold]
bad = number_of_sums - good
print(good)
print(bad)
which I obtain in less than 12 seconds.
cartesian_product = itertools...
; 这篇帖子中的答案似乎会有所帮助。 - user7345804