组合组合

时间:2019-06-03 20:49:49

标签: python

从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))

2 个答案:

答案 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)