题目简述
将整数n,划分为m个整数的和 ( 1 ≤ m ≤ n ) (1 \le m \le n) (1≤m≤n),求有多少种加法结果。
- 额外条件: 整数的顺序也影响结果。
解决方案
解法一、枚举
思考
联想到抽屉原理
-
将整数n理解为有n个item,将枚举过程理解为,将n个item放到m个抽屉中
-
现在的问题就在于如何分配item?
容易得出,两种极端情况。
- m = n m = n m=n,抽屉数等于item个数,这意味着只有一种分法
- m = 1 m = 1 m=1,只有一个抽屉,怎么分都也是只有一种分法
那么,就剩下一种最一般的情况了。
-
n
>
m
n > m
n>m, 抽屉的个数小于item个数
思路:先给每个抽屉都派一个item,盈余的item数surplus为 n − m n - m n−m,
然后,将surplus按照其公因数分配到抽屉中(那么k个公因数也就有k种抽屉分配情况),构造出所有的抽屉,再计算所有抽屉的组合数之和,即计算结果。
- 注意:对于由于 n > m n > m n>m 即使是加上盈余也存在越界的可能,而且某些情况下会产生重复,那么我们可以规定份数乘以抽屉数不能小于盈余来避免。
python代码实现:
from itertools import permutations
# 计算排列组合个数
def combines(_set):
return len(set(permutations(_set, len(_set))))
def get_cnt(_desk, _num):
if _num < 0 or _desk < 0:
return 0
if _desk == 1 or _desk == _num: # 两种特殊的情况
return 1
cnt = 0 # 累计当前所有排列可能
surplus = _num - _desk # 给每个抽屉分配一个item后的盈余的个数
shares = (x for x in range(1, surplus + 1) if surplus <= x * _desk) # 盈余个数的可划分份数集
# 根据每次放入不同的份数,构造不同的抽屉
for x in shares:
tmp = surplus
drawers = [1] * _desk # 生成抽屉并向每个抽屉放入一个item
index = 0
while tmp > 0:
if tmp < x: # 剩余的盈余数少于单份放入抽屉的数量
drawers[index] += tmp
tmp = 0
else:
drawers[index] += x
tmp -= x
index += 1
cnt += combines(drawers) # 计算序列组合数
return cnt
def solution():
cnt = 0
n = int(input("请输入整数n:"))
for i in range(1, n + 1):
cnt += get_cnt(i, n)
return cnt
print(solution())