整数划分问题的递归解法

转自https://www.skymoon.biz/archives/192

整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:

n=m1+m2+…+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,…,mi}为n的一个划分。
如果{m1,m2,…,mi}中的最大值不超过m,即max(m1,m2,…,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);
例如但n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};
注意4=1+3 和 4=3+1被认为是同一个划分。
该问题是求出n的所有划分个数,即f(n, n)。下面我们考虑求f(n,m)的方法;

根据n和m的关系,考虑以下几种情况:
(1)当n=1时,不论m的值为多少(m>0),只有一种划分即{1};
(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,…,1};
(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:
(a). 划分中包含n的情况,只有一个即{n};
(b). 划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。
因此 f(n,n) =1 + f(n,n-1);
(4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);
(5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:
(a). 划分中包含m的情况,即{m, {x1,x2,…xi}}, 其中{x1,x2,… xi} 的和为n-m,可能再次出现m,因此是(n-m)的m划分,因此这种划分
个数为f(n-m, m);
(b). 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);
因此 f(n, m) = f(n-m, m)+f(n,m-1);

综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:
f(n, m)= 1; (n=1 or m=1)
f(n, n); (n<m)
1+ f(n, m-1); (n=m)
f(n-m,m)+f(n,m-1); (n>m)

 1 #include<stdio.h>
 2
 3 int equationCount(int, int);
 4
 5 int main(void)
 6 {
 7     int num;
 8
 9     while(scanf("%d", &num) != EOF)
10         printf("%d\n", equationCount(num, num));
11
12     return 0;
13 }
14
15 int equationCount(int n, int m)
16 {
17     if(n < 1 || m < 1)
18         return 0;
19     if(n == 1 || m == 1)
20         return 1;
21     if(n < m)
22         return equationCount(n, n);
23     if(n == m)
24         return equationCount(n, m - 1) + 1;
25     return equationCount(n, m - 1) + equationCount(n - m, m);
26 }
时间: 2024-10-27 18:50:16

整数划分问题的递归解法的相关文章

整数划分问题(递归法 或 母函数法 )

样题:sdut2015寒假结训赛 开始我还以为是用背包来做,但是写完了代码,怎么写就是不对,并且在实现的时候确实有点地方我用背包的算法描述不了! 后来查到可以用:递归 或者 母函数算法! 比赛时曾考虑过用递归来实现,但没有推导出来,后来发现别人的博客里面写着“整数划分问题”应该在讲解递归的时候就该学会了. 我的心里顿时感到一股抱怨和悔恨,唉!当然自己的责任最大! 整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及.所谓整数划分,是指把一个正整数n写成如下形式:

算法课程小记—递归(整数划分问题)

[例2-5]整数划分问题 在正整数n的所有不同划分中,最大加数n1不大于m的划分个数记做q(n,m).可以建立q(n,m)的如下递归关系. (1)q(n,1)=1,n≥1 当最大加数n1不大于1时,任何正整数n只有一种划分形式,即n=1+1+…+1.(n个1) (2)q(n,m)=q(n,n),m≥n 最大加数n1实际上不大于n.因此q(1,m)=1. (3)q(n,n)=1+q(n,n-1) 正整数n的划分由n1=n的划分和n1≤n-1的划分组成. (4)q(n,m)=q(n,m-1)+q(n

整数划分问题(仅仅显示种类数)

这边博客对于整数划分问题,仅仅要求求出对于每个整数可以划分的种类数,採用金典的递归的办法解决. #include<iostream> using namespace std; /* *整数划分问题(仅仅显示种类数) */ int GetIntDivision(int n,int m) { if(n==1&&m>=1) return 1; if(n>=1&&m==1) return 1; if(m>n) return GetIntDivision

04-07递归解法问题

递归解法问题 从键盘输入一个整数(1~20) 则以该数字为矩阵的大小,把1,2,3-n*n 的数字按照顺时针螺旋的形式填入其中.例如: 输入数字2,则程序输出: 1 2 4 3 输入数字3,则程序输出: 1 2 3 8 9 4 7 6 5 输入数字4, 则程序输出: 1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 7 请使用递归解法解决该问题 04-07递归解法问题

斐波那契数列的递归和非递归解法

//递归解法 function fib(n){ if(n < 1){ throw new Error('invalid arguments'); } if(n == 1 || n == 2){ return 1; } return fib(n - 1) + fib(n - 2); } //非递归解法 function fib(n){ if(n < 1){ throw new Error('invalid arguments'); } if(n == 1 || n == 2){ return 1

7219:复杂的整数划分问题

题目链接:http://noi.openjudge.cn/ch0207/7219/ 总时间限制:  200ms 内存限制:  65536kB 描述 将正整数n 表示成一系列正整数之和,n=n1+n2+-+nk, 其中n1>=n2>=->=nk>=1 ,k>=1 .正整数n 的这种表示称为正整数n 的划分. 输入 标准的输入包含若干组测试数据.每组测试数据是一行输入数据,包括两个整数N 和 K. (0 < N <= 50, 0 < K <= N) 输出

二叉树中节点的最大距离(树的最长路径)——递归解法

上一篇文章说的是该题的一种变形,并给出了非递归解法. 现在我给出原题的一种递归解法.将会看到,现比较上篇博文,今天给出的递归解法的代码实现是相当简洁的. 问题描述: 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数. 写一个程序,求一棵二叉树中相距最远的两个节点之间的距离.测试用的树: n1 /             \ n2             n3 /        \ n4          n5 /     \    

九连环-递归解法

//求取下n环和放上n环的步数 int ans; //规则一:第一环可以在任何时候放上或取下环柄. //规则二:只有紧跟在领头环后的环可以放上或取下环柄.(领头环是套在柄上的最前面的环 int DownRing(int); int UpRing(int); int DownRing(int n) { int res = 0; if(n == 1) return 1; if(n>2) res = (res + DownRing(n-2))%SMod; //移下n-2个,第n-1个变为领头环 res

变形二叉树中节点的最大距离(树的最长路径)——非递归解法

问题描述: 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数. 写一个程序,求一棵二叉树中相距最远的两个节点之间的距离.测试用的树: n1 /             \ n2             n3 /        \ n4          n5 /     \         /   \ n6    n7    n8    n9 /                       / n10