7-37 整数分解为若干项之和 (20 分)
将一个正整数N分解成几个正整数相加,可以有多种分解方法,例如7=6+1,7=5+2,7=5+1+1,…。编程求出正整数N的所有整数分解式子。
输入格式:
每个输入包含一个测试用例,即正整数N (0<N≤30)。
输出格式:
按递增顺序输出N的所有整数分解式子。
递增顺序是指:对于两个分解序列 N1 = {n1,n2,⋯} 和 N2 = {m1,m2,⋯}
若存在 i 使得 n1 = m1 , ⋯ , ni = mi,但是 ni+1 < mi+1 ,则 N1 序列必定在 N2 序列之前输出。
每个式子由小到大相加,式子间用分号隔开,且每输出4个式子后换行。
输入样例:
7
输出样例:
7=1+1+1+1+1+1+1;7=1+1+1+1+1+2;7=1+1+1+1+3;7=1+1+1+2+2
7=1+1+1+4;7=1+1+2+3;7=1+1+5;7=1+2+2+2
7=1+2+4;7=1+3+3;7=1+6;7=2+2+3
7=2+5;7=3+4;7=7
解题思路
这个题目很显然应该用递归的想法去做,但是退出条件和递归式子还需要仔细琢磨。
先做例子分析F(5)的结构
可以看到,数字始终是呈现递增的形式,无论是上下还是左右,都是后面的数字比前面的数字更大。
而且 第1位 数除了其本身,都不会超过 F(n) 中的 n/2 ,然后就是一种n的本身的特殊情况。
如果我们把第一位数设为 i ,将从 i 开始的 F(n),记为 F(n , i )
那么 F(5) 就可以拆分成 F(5,1) , F(5,2) ,F(5,5)三种情况。
F(5,1) 又可以看成是 1 + F(4) , F(4) 则可以看成 F(4,1) , F(4,2) , F(4,4) ...
又或者可以看成是 2 + F(3,2) , F(3,2) 可以拆分为 F(3,3) 因为 F(3,2) 的从 2 开始,而 2 > 2/3,所以舍去了,...
根据以上观察可以发现,只有在 F(n,n)的时候,条件才会结束,并且最后的那一位数字就是 n ,而前面的那一串加法数与上一级相同。
所以我们可以把上一级的前面那一串加法数,传到本级,然后决定在末尾加上 a+ 以后传递到下级,或者是直接输出。
于是式子被改造成F(n , i , str) , n 就是需要求式子的和数,i 就是本级运算需要放在式子第一位的最小数字,str就是上一级传下来的需要被输出的字符串,即图中 1+1+F(2,2) 中的 '1+1+' ,2+F(3,2) 的 该式子写法就是 F(3,2, '2+')。
我这么写可能理解起来有些困难,我还是直接放代码吧,配合代码理解起来应该会更容易。
代码不多,主要算法代码只有十几行。
最终答案
def main():
# 输入,起始条件
n = int(input())
f(n,1,str(n)+'=')
#计数换行,全局变量
count = 0
def f(n, startnum,out=''):
global count
# 递归,从 startnum ,到 n/2 取整 ,range()特性 +1
# 用 out字符串 来存储前面的数字,outmp是当前式子用的,输出即弃用
for i in range(startnum,n//2 + 1):
outmp = out
outmp += str(i) + '+'
f(n-i,i,outmp)
# 退出条件就是 startnum == n,把前面的 out字符串 输出,然后 n 直接输出在末尾就行
# 判断是否换行,最后一个没有';',用是否包含 '+' 取了巧规避了
# 由于这是最后一位数,所以也能控制 '+' 不会添加在末尾
if n == startnum:
print(out + str(n),end='')
count += 1
if (count % 4) ==0:
print()
elif '+' in out:
print(';',end='')
return
# 最后当然还要输出一个前面没有加和的整数
# if startnum < n:
f(n,n,out)
main()
参考资料
感谢以下资料在解决该问题时提供的帮助,大家也可以参考看看。
这篇是递归方式
7-37 整数分解为若干项之和(20 分)- lingr7
这篇用了递推方式
PTA_数据结构学习与实验指导_题解_2-2.5 整数分解为若干项之和 - 满眼星辰