如果没有重复,这将非常容易。. . 为了
{ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
由于您只有 9 个不同的选择(而不是原始问题中的 10 个),因此答案应该是 9!/(9 - 4)!
(顺便说一句,如果允许重复,实际上可以有更多不同的 4 位数字,即 4456。那么答案就是 9^4 个 4 位数字。)
同样,{1, 1, 2, 2, 3, 4, 5, 6, 7, 8 } 有 8 个不同的选择,所以答案应该是 8!/(8 - 4)!由你原来的数学。
编辑和实际答案:也许您的意思是如果 1 在您的集合中重复,您可以在答案中使用两个 1?
编辑 2:提供工作的、经过测试的 python 模块
在这种情况下,您可以尝试计算不同的可能性数量,然后将结果与重复项相加,如以下 python 代码所示):
import math
def set_exclude(a, b):
result = []
for i in a:
if not i in b:
result.append(i)
return result
def cnt_unique(aset, choices_picked, count_left, count_total):
# Sanity check
if count_left < 0:
return 0
if count_left == 0:
return math.factorial(count_total)
# Do non-duplicate combinations first
# Set unprocessed = (set without any elements in choices_picked)
unprocessed = set_exclude(aset, choices_picked)
temp = len(set(unprocessed))
# If we have no more valid items to choose from, this is impossible
if temp >= count_left:
result = math.factorial(temp) / math.factorial(temp - count_left) / \
math.factorial(count_left) * math.factorial(count_total)
else:
result = 0
# Now find duplicate-involving combinations
for member in set(unprocessed):
valid = True
for contest in choices_picked:
if contest >= member:
valid = False
break
if valid:
count = unprocessed.count(member)
new_choices = choices_picked + [ member ]
for i in range(2, count+1):
result_temp = cnt_unique(aset, new_choices, \
count_left - i, count_total)
if result_temp != 0:
result_temp //= math.factorial(i)
result += result_temp
return result
aset = [ 1, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
result_size = 4
combinations = cnt_unique(aset, [], result_size, result_size)
好的,我已经手动验证了该算法适用于您上面介绍的所有案例。我相当有信心它适用于更一般的情况,但我目前没有时间做任何额外的测试用例(例如,如果有 3 个 1 或 3 组重复)。请注意,如果 set 中没有未在 selection_picked 中的数字(即您有一个唯一数字重复 10 次),它也会爆炸。
编辑 3:关于使用此算法对大集合进行多少次函数调用,我使用以下函数调用进行了测试,每次对 cnt_unique 的非平凡(count_left >= 0)调用增加一个变量一次:
>>> def test():
b = [0]
c = time.time()
result = cnt_unique(range(1,51) + range(1,51), [], 4, 4, b)
c = time.time() - c
print("Result: " + str(result))
print("Time: " + str(c))
print("Calls: " + str(b[0]))
>>> test()
Result: 6240150
Time: 0.0150001049042
Calls: 1276
因此,对于 100 个元素集,每个数字 1-50 有 2 个条目,有 1276 个调用。它执行得非常快;time.time() 的一个刻度是 15 毫秒,因此它的执行时间通常少于 15 毫秒。