整数划分问题详解:一个递归算法的诞生与优化
创作时间:
2025-01-22 04:24:29
作者:
@小白创作中心
整数划分问题详解:一个递归算法的诞生与优化
整数划分问题是组合数学中的一个经典问题,具有广泛的应用场景,如计算机科学、密码学等。本文将深入探讨整数划分问题的递归求解方法,并给出具体的代码实现。
问题定义与记号引入
我们首先引入记号q(n,m),表示在正整数n的所有不同划分中,最大加数n1不大于m(即n1≤m)的划分个数。本题要求的p(n),实际上就是q(n,n)。
递推式的推导
分析整数6的11种不同划分的构成,可以得到一个最重要的递推式子:当1<m<n时,q(n,m)=q(n-m,m)+q(n,m-1)。如下图所示。
当n=6,m=3时,有:q(6,3)=q(6-3,3)+q(6,2),q(6,3)表示最大加数不超过3的划分数,即虚线以下3行包括的划分,其中第一行是3开头的划分,个数是q(6-3,3),即从6中扣除3,剩下的值(即3)的最大加数不超过3的划分,后两行是q(6,2),表示最大加数不超过2的划分数
再补充一些边界情形,就可以建立q(n,m)的递归关系(n,m均为≥1的整数):
- 当n=1或m=1时,q(n,m)=1
- 当最大加数n1不大于m=1时,任何正整数n只有一种划分形式,即n=1+1+…+1
- 而当n=1时,也只有一种划分形式,即n=1
- 当m>n时,q(n,m)=q(n,n)
- 最大加数n1实际上不能大于n,因此当m>n时,q(n,m)=q(n,n)
- 当n=m时,q(n,m)=q(n,n)=1+q(n,n-1)
- 正整数n的划分由n1=n的划分(只有1种划分,就是n本身)和n1≤n-1的划分组成。
- 当n>m>1时,q(n,m)=q(n,m-1)+q(n-m,m)
- 正整数n的最大加数n1不大于m的划分(个数为q(n,m),由n1=m的划分(个数为q(n-m,m)和n1≤m-1的划分(个数为q(n,m-1)组成
因此,可以得到下式所示的递推关系。这个递推式子很容易转换成一个递归函数,从而本题可以用递归方法求解。
初始递归代码实现
#include<iostream>
using namespace std;
long long q(int n, int m){
if(n<1 || m<1) return 0;
else if(n==1 || m==1) return 1;
else if(m>n) return q(n, n);
else if(n==m) return (q(n, n-1)+1);
else return (q(n, m-1)+q(n-m, m));
}
int main()
{
int n;
while(cin >> n)
cout << q(n,n) << endl;
return 0;
}
代码优化
由于初始递归代码在大数据时会运行超时,因此需要进行优化。引入二维数组record,record[n][m]记录求得的q(n,m)。
#include<iostream>
using namespace std;
long long record[401][401]; //全局变量,编译器将各元素值初始化为0
long long q(int n, int m){
if(record[n][m]) return record[n][m];
if(n<1 || m<1) return record[n][m]=0;
else if(n==1 || m==1) return record[n][m]=1;
else if(m>n) return record[n][m]=q(n, n);
else if(n==m) return record[n][m]=(q(n, n-1)+1);
else return record[n][m]=(q(n, m-1)+q(n-m, m));
}
int main()
{
int i, j, n;
for(i=1;i<=400;i++){ //求出所有的q(n,m)
for(j=1;j<=i;j++) record[i][j] = q(i,j);
}
while(cin >> n)
cout << q(n,n) << endl;
return 0;
}
在优化后的代码中:
- 定义了一个二维数组record,record[n][m]记录求得的q(n,m)
- 在递归函数q里,增加了一条语句:当record[n][m]的值非0,意味着已经求出了record[n][m],则不递归求解,而是直接返回其值
- 每个条件分支里都是先对record[n][m]赋值,再返回record[n][m]的值
- 在main函数里,用一个二重循环求出所有的q(n,m),m≤n≤400,即只求出二维数组record主对角线及以下元素的值
- 最后,对输入的每个n值,答案p(n)=q(n,n)=record[n][n]直接输出即可
下图给出了求得的record数组部分元素的值,根据这些值,也可以验证上述递推式子。需要说明的是,在record数组里,包含了整数1~400的划分数(对角线上的值)。
热门推荐
销售渠道是什么?有哪些常见的销售渠道?
有机合成反应后处理洗涤萃取的标准化操作指南
新团队如何选拔
高级注册安全工程师:提升企业安全管理水平,保障生产安全的关键角色
在校生能否签订劳动合同?这份指南请收好
机动车检测流程详解:从预约到领取合格标志
海南岛深度游攻略:涵盖美食、景点、住宿与交通全指南
探究富足的近义词:财富、富裕、丰富、充实
环境污染检测仪器与环境数据分析的整合
封神演义:三霄仙子若杀玉虚十二仙,将引发怎样的连锁反应?
猫咪吃饭的表现与意义:从饮食习性看健康状况
通话服务受限?跟着这篇文章,一步解决电话拨打难题!
劳动合同第二次续签有年限限制吗
小区类型分为哪几类?
未来适合发展转行的职业方向—基于民营企业座谈会政策的机遇分析
一文读懂Mesh组网,安排!
高位炸板频现,A股三大指数小幅上涨,TMT赛道领涨
招聘中的性格测评工具的效果如何评估
为什么电水壶指示灯不亮?故障排查指南
桃树修剪后怎样防止伤口感染腐烂
忘记BitLocker PIN?教你轻松恢复加密驱动器
96年火箭4换1得到巴克利,组三巨头冲三连冠,后来这四人发展如何
MQTT协议原理与特性详解
西藏定日县地震已致126人遇难、188人受伤
Web开发中防止中文乱码的全面指南
玄关餐边电视柜一体化设计,既整洁美观又实用,打造完美家居空间
中科大专业:国内顶尖,国际一流
中国地大物博,每个地方都有不同的特产,那么你家乡有什么特产呢
PCB寄生电容的影响、计算方法和消除措施
挖笋技巧与方法:传承老经验,享受山野美味