算法设计与分析之递归算法练习(下)
递归算法八:集合全排列问题
分析
当n=1时,
perm( R )=( r ),其中r是集合R中唯一的元素;
当n>1时,perm( R )由
(r1) perm(R1)
(r2) perm(R2)
…
(rn) perm(Rn)构成。
代码
void perm(int args[], int k, int m){
if(k==m){
for(int i=0;i<=m;i++)
cout<<args[i]<<" ";
cout<<endl;
}
else
for(int j=k;j<=m;j++) {
swap(args[k],args[j]);
perm(args,k+1,m);
swap(args[k],args[j]);
}
}
递归算法九:整数划分问题
分析
整数6的划分方法数 =
最大加数不大于6的划分方法数
最大加数不超过6的分解方法数
=最大加数不超过5的分解方法数
+最大加数等于5的分解方法数
即q(6,6) = q(6,5) + q(0,6)
以此类推
代码
int integerDivision(int n,int m){
if(n<1)
return 0;
else if(n==1||m==1)
return 1;
else if(n<m) return integerDivision(n,n);
else if(n==m) return integerDivision(n,m-1)+1;
return integerDivision(n,m-1)+integerDivision(n-m,m);
}
递归算法十:排队购票
问题描述
一场球赛开始前,售票工作正在紧张进行中。
每张球票为50元,
有m+n个人排队等待购票,
其中有m 个人手持50元的钞票,
另外n个人手持100元的钞票。
求出这m+n个人排队购票,使售票处不至出现找不开钱的局面的不同排队种数 。
(约定:开始售票时售票处没有零钱;拿同样面值钞票的人对换位置为同一种排队。)
分析
(1) n = 0,即所有人都拿50元的钞票,queueNum(m,n) = 1;
(2) m < n时,即使所有50元的钞票都找零也找不开,所以queueNum(m,n) = 0;
(3)
1) 第m+n个人如果拿的100元钞票,那么总共的排队数量为queueNum(m,n-1);
2) 第m+n个人如果拿的50元钞票,那么总共的排队数量为queueNum(m-1,n);
综上,第三种情况的排队数:queueNum(m,n) = queueNum(m,n-1) + queueNum(m-1,n);
代码
int queueNum(int m, int n){
if(n == 0) return 1;
if(m < n) return 0;
return queueNum(m-1,n) + queueNum(m,n-1);
}
递归算法十一:杨辉三角
分析
1、采用二维数组存储
2、对角线初始化为1,第一列初始化为1
3、其余情况yangHuiTriangle(i-1,j)+yangHuiTriangle(i-1,j-1);
代码
#include <iostream>
using namespace std;
const int N = 100;
int yangHuiTriangle(int i, int j);
int main()
{
int n;
cout<<"请输入杨辉三角的行数:";
cin>>n;
for(int i = 0;i < n;i++) {
for(int j = 0;j <= i;j++)
cout<<yangHuiTriangle(i,j)<<"\t";
cout<<endl;
}
return 0;
}
int yangHuiTriangle(int i, int j){
if(i == j) return 1;
if(j == 0) return 1;
return yangHuiTriangle(i-1,j) + yangHuiTriangle(i-1,j-1);
}
递归算法十二:计算两个数的最大公约数
分析
求最大公约数是个经典问题,我们这里介绍两种解决方法。
方法一:更相减损
除非两数相等,否则两数中最大数和最小数的差值与最小数的公约数即为两数的公约数。
方法二:辗转相除
除非两数求余为零,否则后数与前数对后数的取余值的公约数即为两数的公约数。
代码
//更相减损
int mcdMethod1(int num1,int num2){
if(num1 == num2) return num1;
else if(num1 > num2) return mcdMethod1(num1-num2,num2);
else return mcdMethod1(num2-num1,num1);
}
//辗转相除
int mcdMethod2(int num1,int num2){
if(num2) return mcdMethod2(num2,num1%num2);
return num1;
}
递归算法十三:计算一个正整数中所有的数字之和
分析
除非正整数为零,否则整数除以十的结果与正整数取余十的和即为最后结果。
代码
int sumNum(int num){
if(num) return sumNum(num/10) + num%10;
return num;
}
递归算法十四:求(1+1/2+1/3+…+1/n)的和
分析
如果n = 1,返回1;否则返回sum(n-1) + 1.0/n。
代码
double sum(int n){
if(n == 1) return 1;
return sum(n-1) + 1.0/n;
}