从1-49范围内的6个数字中选择了将近1400万个组合。通过仅选择6个数字组合之和必须等于120到180之间的组合,我将组合减少到890万。
例如:5、10、20、27、29、40 = 131
在剩余的890万个组合中,我试图删除包含少于2个和大于4个奇数的所有组合。
基本上,我希望Python能够向我展示890万个组合中有多少个组合的2-4个奇数。结果中将排除仅1个或更少的奇数和5个或更多的奇数的所有组合。
例如:5、10、20、27、32、40 = 2个奇数(将包含在组合数量中)。
谢谢!
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
@functools.lru_cache(maxsize=None)
def f(n, l, s):
assert(all(isinstance(v, int) and v >= 0 for v in (n, l, s)))
return 0 if s > _MAX_SUM else (
int(s >= _MIN_SUM) if n == 0 else (
sum(f(n-1, i+1, s+i) for i in range(l, _MAX_NUM+1))
)
)
result = f(_NUM_CHOICES, _MIN_NUM, 0)
print('Number of choices = {}'.format(result))
答案 0 :(得分:2)
您可以使用itertools中的groups()函数,然后简单地计算出符合条件的组合:
from itertools import combinations
eligible = 0
for combo in combinations(range(1,50),6):
total = sum(combo)
if total < 120 or total > 180:
continue
odds = sum(n&1 for n in combo)
if odds < 2 or odds > 4:
continue
eligible += 1
print(eligible) # 7221936
只需要几秒钟(10-12)
答案 1 :(得分:0)
您可以执行几乎与当前相同的操作。只需添加一个计算有多少个奇数的参数,并在添加奇数时增加它。然后,您可以相应地调整测试:
import functools
_MIN_SUM = 120
_MAX_SUM = 180
_MIN_NUM = 1
_MAX_NUM = 49
_NUM_CHOICES = 6
_MIN_ODDS = 2
_MAX_ODDS = 4
@functools.lru_cache(maxsize=None)
def f(n, l, s = 0, odds = 0):
if s > _MAX_SUM or odds > _MAX_ODDS:
return 0
if n == 0 :
return int(s >= _MIN_SUM and odds >= _MIN_ODDS)
return sum(f(n-1, i+1, s+i, odds + i % 2) for i in range(l, _MAX_NUM+1))
result = f(_NUM_CHOICES, _MIN_NUM)
print('Number of choices = {}'.format(result))
因为它已被记忆并修剪了分支,所以运行很快:
150 ns ± 13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
以更易于管理的方式运行它:
_MIN_SUM = 1
_MAX_SUM = 8
_MIN_NUM = 1
_MAX_NUM = 8
_NUM_CHOICES = 2
_MIN_ODDS = 2
_MAX_ODDS = 4
返回与集合相对应的4
:
(1, 3),
(1, 5),
(1, 7),
(3, 5)