1.非递归方式:
# -*- coding: utf-8 -*-
# @Time : 2020/9/24 17:16
# @Author : wmy
"""
问题描述: 从一个集合[0,1,...,K]中取出P个数,组成一个排列(数字可以重复取),使它们的和为K,求所有可能的排列数?
解决方法:
step1:条件约束下的有放回采样,计算包含P个数的集合且集合之和为K的所有组合
step2:针对每个可能包含重复元素的组合,计算其全排列数,然后累加
examples:
- K=5
- N=3
组合:[0,0,5],[0,1,4],[0,2,3],[1,1,3],[1,2,2]
排列:[0,0,5] - 3
[0,1,4] - 6
[0,2,3] - 6
[1,1,3] - 3
[1,2,2] - 3
结果: 3+6+6+3+3 = 21
"""
import math
class PermutationQuantity:
def __init__(self, K, P):
self.quantity = 0
self.K = K
self.P = P
def combinations(self):
"""
计算包含P个数的集合且集合之和为K的所有组合
:return:
"""
if not self.K and self.P:
return
indices = [0] * self.P
while True:
# for ...else :当迭代对象完成所有迭代后且此时的迭代对象为空时,如果存在else子句则执行else子句,没有则继续执行后续代码;
# 如果迭代对象因为某种原因(如带有break关键字)提前退出迭代,则else子句不会被执行,程序将会直接跳过else子句继续执行后续代码
for i in reversed(range(self.P)):
if indices[i] != self.K:
indices[i:] = [indices[i] + 1] * (self.P - i)
break
# if sum(indices) == self.K:
else:
return
if sum(indices) == self.K:
self.quantity += self.permutations(indices)
def permutations(self, s):
"""
计算包含重复元素的集合的排列数
:param s:
"""
num_dict = dict()
for e in s:
if e in num_dict.keys():
num_dict[e] += 1
else:
num_dict[e] = 1
n = math.factorial(len(s))
for key, value in num_dict.items():
n /= math.factorial(value)
return n
def run(self):
self.combinations()
return int(self.quantity)
if __name__ == '__main__':
K = 5
P = 4
pq = PermutationQuantity(K, P)
quantity = pq.run()
print(quantity)
2.递归方式
# -*- coding: utf-8 -*-
# @Time : 2020/9/20 01:16
# @Author : wmy
"""
问题描述: 从一个集合[0,1,...,K]中取出P个数,组成一个排列(数字可以重复取),使它们的和为K,求所有可能的排列数?
解决方法:
step1:条件约束下的有放回采样,计算包含P个数的集合且集合之和为K的所有组合
step2:针对每个可能包含重复元素的组合,计算其全排列数,然后累加
examples:
- K=5
- N=3
组合:[0,0,5],[0,1,4],[0,2,3],[1,1,3],[1,2,2]
排列:[0,0,5] - 3
[0,1,4] - 6
[0,2,3] - 6
[1,1,3] - 3
[1,2,2] - 3
结果: 3+6+6+3+3 = 21
"""
import math
class Quantity:
def __init__(self, M, N):
self.quantity = 0
self.M = M
self.N = N
self.comb_list = list()
def calc_quantity(self, m, n, sum, M, N, li):
if m > M:
return
if n + 1 == N:
if M - sum >= m:
li[n] = M - sum
self.quantity += self.calc_permutation_quantity(li)
return
if m + 1 + sum > M:
return
self.calc_quantity(m + 1, n, sum, M, N, li)
if (m << 1) + sum > M:
return
li[n] = m
self.calc_quantity(m, n + 1, sum + m, M, N, li)
def calc_permutation_quantity(self, li):
"""
计算包含重复元素的集合的排列数
:param li:
"""
num_dict = dict()
for e in li:
if e in num_dict.keys():
num_dict[e] += 1
else:
num_dict[e] = 1
n = math.factorial(len(li))
for key, value in num_dict.items():
n /= math.factorial(value)
return n
def run(self):
li = [0 for i in range(self.N)]
self.calc_quantity(0, 0, 0, self.M, self.N, li)
return int(self.quantity)
if __name__ == '__main__':
M = 100
N = 10
pq = Quantity(M, N)
print(pq.run())