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

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

导读


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


递归


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

递归一般分为两个阶段:


递推


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


回归


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


问题一般形式


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

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


爬楼梯问题:


假设你正在爬楼梯。需要 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

目录
相关文章
|
存储 算法
蓝桥杯:递归 与 例题:斐波那契数列及优化与应用
蓝桥杯:递归 与 例题:斐波那契数列及优化与应用
80 0
|
6月前
代码随想录Day32 动态规划01 LeetCodeT509 斐波那契数列 T70 爬楼梯 T746 爬楼梯的最小消耗
代码随想录Day32 动态规划01 LeetCodeT509 斐波那契数列 T70 爬楼梯 T746 爬楼梯的最小消耗
48 0
递归经典例题——汉诺塔
递归经典例题——汉诺塔
109 1
浅谈递归函数(最后一个例题:浅谈汉诺塔思路与代码)
浅谈递归函数(最后一个例题:浅谈汉诺塔思路与代码)
|
算法 Java Linux
【基础算法】二分例题(我在哪?)
【基础算法】二分例题(我在哪?)
117 0
【基础算法】二分例题(我在哪?)
|
C语言
【C】青蛙跳台阶和汉诺塔问题(递归)
【C】青蛙跳台阶和汉诺塔问题(递归)
124 0
【C】青蛙跳台阶和汉诺塔问题(递归)
(蓝桥杯)递推与递归,前缀和,二分经典例题分析
(蓝桥杯)递推与递归,前缀和,二分经典例题分析
(蓝桥杯)递推与递归,前缀和,二分经典例题分析
|
机器学习/深度学习 算法 C++
(C/C++)STL函数(3)二分算法题以及二分模板 和(蓝桥杯)递推与递归题目及解法(ACwing)
(C/C++)STL函数(3)二分算法题以及二分模板 和(蓝桥杯)递推与递归题目及解法(ACwing)
(C/C++)STL函数(3)二分算法题以及二分模板 和(蓝桥杯)递推与递归题目及解法(ACwing)
|
算法 Java
【递归与回溯算法】汉诺塔与八皇后问题详解
文章目录 1 汉诺塔问题 1.1 汉诺塔问题概述 1.2 思路分析 1.3 代码实现(Java) 1.4 结果验证 2 八皇后问题 2.1 八皇后问题概述 2.2 思路分析 2.2.1 问题划分与分析 2.2.2 涉及到的数据结构分析 2.2.3 上下对角线与行列的关系 2.3 代码实现(Java) 2.4 结果验证
【递归与回溯算法】汉诺塔与八皇后问题详解