假设我们有x
苹果和y
篮子,我们想把所有苹果分配到篮子,这样每个篮子最多得到z
苹果。如何编写Python代码以获得所有可能的组合。对于少量的y
,我可以按照以下方式对y
进行循环(x = 5,y = 3,z = 2)。
all_chances = np.zeros((0,3))
for a in range(3):
for b in range(3):
for c in range(3):
if a+b+c == 5:
all_chances = np.vstack((all_chances, np.array([a,b,c])))
基本上,all_chances
是
array([[1., 2., 2.],
[2., 1., 2.],
[2., 2., 1.]])
我的问题是:如果y是一个大数字,如x = 30,y = 26,z = 2,该怎么办?我需要循环26次吗?
我搞砸了你的问题...尝试实施一种基于树的方法bc我认为它很聪明,但我的笔记本电脑呛到它。我很好奇有多少排列我们正在寻找这些大数字,并改变了问题(对我自己)简单地计算排列,看看它是否在轻量级笔记本电脑上是可行的。
我得到154,135,675,070个独特的排列。
开始...我用itertools搞砸了,并且排列长度为26的列表。所以...提醒自己长期被遗忘的公式至少计算不同的排列,我发现这个... https://socratic.org/questions/how-many-distinct-permutations-can-be-made-from-the-letters-of-the-word-infinity
有了这个,我运行以下来计算。它运行在一秒钟之内。
from numpy import prod
from math import factorial
import itertools
# number of unique permutations
def count_distinct_permutations(tup):
value_counts = [len(list(grp)) for _, grp in itertools.groupby(tup)]
return factorial(sum(value_counts)) / prod([float(factorial(x)) for x in value_counts])
# starting values
x = 30 # apples
y = 26 # baskets
z = 3 # max per basket
# count possible results
result = 0
for combos in itertools.combinations_with_replacement(range(z), y):
if sum(combos) == x:
result += count_distinct_permutations(combos)
现在......这显然不能回答你的具体问题。老实说,无论如何,我无法保持你在内存中寻找的结果。但是......你可以用这个来推断......用你选择的值,只有12种值的组合,但每种组合的排列在15k到5000万之间。
您可以查看每个组合...在count_distinct_permutations()
函数中,itertools.groupby
为您提供(0,1,2)
中每个数字的组合数,并且您可以使用这12个结果中的每一个来推断某些内容。不确定是什么,但我也不太确定如何处理长达15.44亿个长度的列表。:)
希望这里有一些有用的东西,即使它没有回答你的确切问题。祝好运!
这是一种基于Young图的方法。例如,每个篮子有4个篮子,6个鸡蛋,最多3个鸡蛋。如果我们按照它们的充分程度订购篮子,我们就会得到年轻的图表。
x x x x x x x x x x x x x x x x
x x x x x x x x x x
x x x x
下面的代码列举了所有可能的Young图表,并列出了所有可能的排列。
也可以使用相同的逻辑来计数。
from itertools import product, combinations
from functools import lru_cache
import numpy as np
def enum_ord_part(h, w, n, o=0):
if h == 1:
d = n
for idx in combinations(range(w), d):
idx = np.array(idx, int)
out = np.full(w, o)
out[idx] = o+1
yield out
else:
for d in range((n-1)//h+1, min(w, n) + 1):
for idx, higher in product(combinations(range(w), d),
enum_ord_part(h-1, d, n-d, o+1)):
idx = np.array(idx)
out = np.full(w, o)
out[idx] = higher
yield out
def bc(n, k):
if 2*k > n:
k = n-k
return np.prod(np.arange(n-k+1, n+1, dtype='O')) // np.prod(np.arange(1, k+1, dtype='O'))
@lru_cache(None)
def count_ord_part(h, w, n):
if h == 1:
return bc(w, n)
else:
return sum(bc(w, d) * count_ord_part(h-1, d, n-d)
for d in range((n-1)//h+1, min(w, n) + 1))
几个例子:
>>> for i, l in enumerate(enum_ord_part(3, 4, 6), 1):
... print(l, end=' ' if i % 8 else '\n')
...
[3 3 0 0] [3 0 3 0] [3 0 0 3] [0 3 3 0] [0 3 0 3] [0 0 3 3] [3 2 1 0] [2 3 1 0]
[3 1 2 0] [2 1 3 0] [1 3 2 0] [1 2 3 0] [2 2 2 0] [3 2 0 1] [2 3 0 1] [3 1 0 2]
[2 1 0 3] [1 3 0 2] [1 2 0 3] [2 2 0 2] [3 0 2 1] [2 0 3 1] [3 0 1 2] [2 0 1 3]
[1 0 3 2] [1 0 2 3] [2 0 2 2] [0 3 2 1] [0 2 3 1] [0 3 1 2] [0 2 1 3] [0 1 3 2]
[0 1 2 3] [0 2 2 2] [3 1 1 1] [1 3 1 1] [1 1 3 1] [1 1 1 3] [2 2 1 1] [2 1 2 1]
[2 1 1 2] [1 2 2 1] [1 2 1 2] [1 1 2 2]
>>>
>>> print(f'{count_ord_part(2, 26, 30):,}')
154,135,675,070
>>> print(f'{count_ord_part(50, 30, 1000):,}')
63,731,848,167,716,295,344,627,252,024,129,873,636,437,590,711