递归算法:
将正整数n表示成一系列正整数之和,n=n1+n2+...+nk,其中n1>=n2>=n3>=...>=nk>=1,k>=1。
正整数n的这种表示称为正整数n的划分。正整数n的不同的划分个数城外正整数n的划分数,记作p(n)。
例如,正整数6有如下11种不同的划分,所以p(6)=11。
6;
5+1;
4+2;4+1+1;
3+3;3+2+1;3+1+1+1;
2+2+2;2+2+1+1;2+1+1+1+1;
1+1+1+1+1+1。
求解:
在正整数n的所有不同的划分中,将最大加数n1不大于m的划分个数记作q(n,m)。可以建立q(n,m)的递推关系。
(1)q(n,1)=1,n>=1。
当最大加数n1不大于1时,任何正整数n只有一种划分形式,即n=1+1+1.....+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-m,m),n>m>1。
正整数n的最大加数n1不大于m的划分是由n1=m的划分和n1<=m-1的划分组成。
综上所述,设计计算q(n,m)的递归算法如下,其中正整数n的划分数p(n)=q(n,n)。
#include<iostream> using namespace std; int q(int n,int m) { if((n<1)||(m<1)) return 0; if((n==1)||(m==1)) return 1; if(n<m) return q(n,n); else if(n==m) return q(n,m-1)+1; return q(n,m-1)+q(n-m,m); } int main() { cout<<q(6,6)<<endl; return 0; }
非递归算法:
同样一个题目,换一种描述方式。
问题描述:
把 M 个同样的苹果放在N 个同样的盘子里,允许有的盘子空着不放,问共有多少
种不同的分法?(用K 表示)注意:5,1,1 和1,5,1 是同一种分法。
输入数据
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含两个整数M 和N,以
空格分开。1<=M,N<=10。
输出要求
对输入的每组数据M 和N,用一行输出相应的K。
输入样例
1
7 3
输出样例
8
解题思路:
所有不同的摆放方法可以分为两类:至少有一个盘子空着和所有盘子都不空。我们可以分别计算这两类摆放方法的数目,然后把它们加起来。对于至少空着一个盘子的情况,则N 个盘子摆放M 个苹果的摆放方法数目与N-1 个盘子摆放M 个苹果的摆放方法数目相同。对于所有盘子都不空的情况,则N 个盘子摆放M 个苹果的摆放方法数目等于N 个盘子摆放M-N 个苹果的摆放方法数目。我们可以据此来用递归的方法求解这个问题。
设f(m, n) 为m 个苹果,n 个盘子的放法数目,则先对n 作讨论,如果n>m,必定有n-m 个盘子永远空着,去掉它们对摆放苹果方法数目不产生影响;即if(n>m) f(m,n) =f(m,m)。当n <= m 时,不同的放法可以分成两类:即有至少一个盘子空着或者所有盘子都有苹果,前一种情况相当于f(m , n) = f(m , n-1); 后一种情况可以从每个盘子中拿掉一个苹果,不影响不同放法的数目,即f(m , n) = f(m-n , n)。总的放苹果的放法数目等于两者的和,即 f(m,n) =f(m,n-1)+f(m-n,n) 。整个递归过程描述如下:
int f(int m , int n){ if(n == 1 || m == 0) return 1; if(n > m) return f (m, m); return f (m , n-1)+f (m-n , n); }
#include<iostream> using namespace std; int dp[101][101]; int solve (int m,int n) { for (int i = 1;i <= n;i++) dp[0][i] = 1; for (int i = 1;i <= m;i++) { dp[i][0] = 0; for (int j = 1;j <= n;j++) { if(i < j) dp[i][j] = dp[i][i]; else dp[i][j] = (dp[i-j][j]+dp[i][j-1]); } } return dp[m][n]; } int main() { int n,m,ans; while(scanf("%d%d",&m,&n)!=EOF) { ans = solve(m,n); printf("%d\n",ans); } return 0; }
参考
王晓东《算法设计与分析(第2版)》P23
程序设计导引及在线实践P178