汉诺塔?爬楼梯?斐波那契?知道递归就够了

简介: 汉诺塔?爬楼梯?斐波那契?知道递归就够了

导读


我们在利用编程解决实际问题时总会遇到这样一种问题,即分解后的子问题与原问题类似,能用原来的方法解决问题,且最终的子问题是已知解或易于解,通常我们可以使用一种特殊的解决问题的方法——递归


递归


其基本思想是:将要解决的问题分解成比原问题规模小的子问题,当解决这个子问题时,又可以用到原问题的解决方法,按照这个原则逐步递推,最终将原问题转换成较小且已知的解的子问题。

递归一般分为两个阶段:


递推


将原问题不断地转化成子问题, 逐渐从未知向己知推进, 最终到达已知解的问题,即递推阶段结束。


回归


从已知解的问题出发,按照递推的逆过程,逐一求值回归, 最后到达递归的开始处,即结束回归阶段,获得问题的解。


问题一般形式


诺可将求解问题逐步转化成与原问题类似的子问题,且最终子问题有明确的解,则可采用递归函数,实现问题的求解。

注:由于在递归函数中存在着调用自身的过程,因此要控制反复进入自身的函数体调用,必须在函数体中设置终止条件,当条件成立时,终止调用自身,并使控制逐步返回到主调函数。


爬楼梯问题:


假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?注意:给定 n 是一个正整数。

解释:有两种⽅法可以爬到楼顶。

输⼊:n = 2

输出:2

第⼀种:1 阶 + 1 阶

第⼆种: 2 阶

题解:这是一道非常经典的例题,通过分析我们不难发现一个这样的规律,当我们第一步只爬一个台阶剩下的n-1个台阶有它的爬法个数,当我们第一步爬两个台阶剩下的n-2个台阶就有它的爬法。以此类推最终我们就可以得到这样一个函数关系式:


ea57add82a5ea01097e0cc6e79a29de3_a464a94b6760453e9d7f51b27fc8a663.png


这明显符合我们递归问题,因此我们可以写出代码:


#include<stdio.h>
int Class(int n) {
  int i = 0;
  if (n == 1)
  return 1;
  if (n == 2)
  return 2;
  return Class(n - 1) + Class(n - 2);
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  printf("%d", Class(n));
}


在我们运算过程中我们会发现总有那么几个数我们需要重复计算,大大的增加了我们的运算量,这里我们可以创造一张记忆表去记录我们已有的n:


#include<stdio.h>
int a[100] = { 0 };//创造记忆体
int b = 0;
int Class(int n)
{
  int i = 0;
  if (n == 1)
  return 1;
  if (n == 2)
  return 2;
  while (i <= b)
  {
  if (n == a[i])
    return a[i];
  }//判断楼梯阶数是否在记忆体中保留过
  int c = Class(n - 1) + Class(n - 2);
  a[b] = c;
  return c;
}
int main()
{
  int n;
  scanf("%d", &n);
  printf("需要爬%d", Class(n));
}```
当然这道题我们同样也可以使用一般循环的解法:
```c
#include<stdio.h>
int Class(int n)
{
  if (n == 1)
  return 1;
  if (n == 2)
  return 2;
  int c = 0;
  int i = 0;
  int pre = 2;
  int prepor = 1;
  for (i = 3;i <= n;i++)
  {
  c = pre + prepor;
  prepor = pre;
  pre = c;
  }
  return c;
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  printf("需要爬%d", Class(n));
}



汉诺塔问题


古代有一个梵塔,塔内有3个座A、B、C,开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上,有一个老和尚想把这64个盘子从A座移到C座,但每次只允许移动一个盘,且移动过程中在3个座上都始终保持大盘在下、小盘在上的状态。在移动过程中可以利用B座,要求编写程序并打印出移动的步骤。

题解:将n个盘子从A座移到C座可以分解为以下三个步骤:


将A座上n-1个盘子借助C座先移到B座上。

将A座上剩下的一个盘子移到C座上。

将n-1个盘子从B座借助A座移到C座上。

如果想将A座上3个盘子移到C座上,可以分解为以下三个步骤:

将A座上2个盘子借助C座移到B座上

将A座上1个盘子移到C座上;

将B座上2个盘子借助A座移到C座上。

其中第(2)步可以直接实现。第(1)步又可用递归方法分解为:

将A座上1个盘子从A座移到C座

将A座上1个盘子从A座移到B座

将C座上1个盘子从C座移到B座

将B座上1个盘子从B座移到A座上

将B座上1个盘子从B座移到C座上

将A座上1个盘子从A座移到C座上。

综合以上情况,可得到移动3个盘子的步骤为:

A→C, A→B,C→B,A→C,B→A,B→C,A→C


1684812276246.png


代码如下:


#include<stdio.h>
void Hanoi(int n, char A, char B, char C)
{
  if (n == 1)
  printf("%c->%c\n", A, C);
  else
  {
  Hanoi(n - 1, A, C, B);
  printf("%c->%c\n", A, C);
  Hanoi(n - 1, B, A, C);
  }
}
int main()
{
  int n = 0;
  scanf("%d", &n);
  Hanoi(n, 'A', 'B', 'C');
  return 0;
}



运行结果如下:


c9767d1fec703a2748758ea08f94089b_4ab9d1374fae4572ae6852e0adebdbe2.png

目录
相关文章
|
存储 算法
蓝桥杯:递归 与 例题:斐波那契数列及优化与应用
蓝桥杯:递归 与 例题:斐波那契数列及优化与应用
87 0
LeedCode_04-斐波那契数列(剑指offer-10)
LeedCode_04-斐波那契数列(剑指offer-10)
【剑指offer】-斐波那契数列-07/67
【剑指offer】-斐波那契数列-07/67
LeetCode题:70爬楼梯,126斐波那契数
LeetCode题:70爬楼梯,126斐波那契数
61 0
剑指offer-9.斐波那契数列
剑指offer-9.斐波那契数列
55 1
|
算法 Java
【洛谷算法题】P5708-三角形面积【入门1顺序结构】
【洛谷算法题】P5708-三角形面积【入门1顺序结构】
剑指offer 09. 斐波那契数列
剑指offer 09. 斐波那契数列
45 0
|
算法
斐波那契数列两种算法和青蛙跳台阶的两种实际问题
当我们看到这样的题时,心想就是一个简单的递归调用么。 但是,我们要看到这种算法的不足之处——效率低下。 首先简单的介绍一下 :
100 0
|
C语言
【C】青蛙跳台阶和汉诺塔问题(递归)
【C】青蛙跳台阶和汉诺塔问题(递归)
128 0
【C】青蛙跳台阶和汉诺塔问题(递归)