递归算法实验(整数分划/汉诺塔/n个数的r组合)
1. 实验环境
Dev C++,使用C/C++语言。
2.实验题目
题目1: 整数分划
要求给出分划方式与分化数目的总和 (例如: n=6, n=8)
题目2: 汉诺塔问题
分别计算 4阶/5阶/6阶汉诺塔问题
题目3: n个数的r组合
3.分析、建模、设计、实验结果、复杂度
题目一:
问题分析:
对于一个正整数n的分划就是把n写成一系列正整数之和的表达式。例如对于正整数n=6,有:
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=8有:
8
7+1
6+2,6+1+1
5+3,5+2+1,5+1+1+1
4+4,4+3+1,4+2+2,4+2+1+1,4+1+1+1+1
3+3+2,3+3+1+1,3+2+2+1,3+2+1+1+1,3+1+1+1+1+1
2+2+2+2,2+2+2+1+1,2+2+1+1+1+1,2+1+1+1+1+1+1
1+1+1+1+1+1+1+1
算法设计:
根据上面例子可以发现≤1行的数据不超过n,≤2行的数据不超过n-1…,≤n行的数据不超过1。因此,定义一个函数Q(n,m),表示整数n的“任何被加数都不超过m”的分划的数目,那么,n的所有分化的数目为:P(n)=Q(n,n)
模型建立:
因此,定义Q(n,m)有以下递归关系:
1.Q(n,n)=1+Q(n,n-1)(m=n)
Q(n,n-1)表示n的所有其他分划,即最大被加数m≤n-1的划分
2.(n,m)=Q(n,m-1)+Q(n-m,m) (m<n)
Q(n,m-1)表示被加数中不包含m的分划的数目Q(n-m,m)表示被加数中包含(注意不是Q小于)m的分划的数目
递归停止的条件:
1.Q(n,1) = 1,表示当最大的被加数是1是,该证书n只有一种分划,即n个1相加;
2.Q(1,m) = 1,表示整数n = 1只有一个分划,不管最大被加数的上限m是多大。
实验结果
复杂度分析
问题二:
问题分析:
在移动过程中可以利用C基座做辅助
算法设计:
1.用归纳法解决问题,给盘子从上到下依次编号为1,2,3…,n
2.用二阶汉诺塔来举例
3.把n个盘子抽象的看作“两个盘子”,上面“一个”由1至(n-1)号组成,下面“一个”就是第n号盘子
4.第一步:先把上面“一个”盘子以A基座为起点借助B基座移到C基座
5.第二步:把下面“一个”盘子从A基座移到B基座;
6.第三步:再把C基座上的n-1盘子借助A基座移到b基座
模型建立:
把n阶的汉诺塔问题的模块记作hanoi(n,a,b,c)
a代表每一次移动的起始基座,
b代表每一次移动的终点基座,
c代表每一次移动的辅助基座;
实验结果
复杂度分析
问题三:
问题分析:
n个数的r组合,其中每r个数中,数不能相同;任何两组组合的数,所包含的数也不应相同。例如,5、4、3与3、4、5是同一个组合。为此,约定前一个数应小于后一个数
算法设计:
在循环算法设计中,对n=5的实例,每个组合中的数据从小到大排列或从大到小排列一样可以设计出相应的算法。但用递归思想进行设计时,每个㓴合中的数据从大到小排列却是必须的;因为递归算法设计是要找出大规模问题与小规模问题之间的关系。
实验结果
复杂度分析
代码展示
整数分划
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//计算划分数量
int divideNumber(int n,int m)
{
if(m==1 || n==1)
return 1;
if(n<m)
return divideNumber(n,n);
else if(n==m)
return divideNumber(n