递归:汉诺塔问题和青蛙跳台阶问题
汉诺塔:汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
其实汉诺塔问题可以用递归解决,假设有n个圆盘,把最大盘子上面全部看成一个整体,就是假设只有两个盘子第n个和n-1个,三个柱子a,b,c,重新移动到另一个柱子上,先把第一个最上层的移动到b柱上
注意此时对于n-1的盘子来说,a是起始柱,b是目标柱,c是过渡柱。
然后把大的盘子移动到c柱上,注意此时对于n来说,a是起始柱子,b是过渡柱,c是目标柱子
然后再把n-1放到c柱上,此时对于n-1来说a是过渡柱,b是起始柱,c是目标柱。
好这个整个一个流程就完成了,可是这不符合题目要求,不是说一次只能动一个盘子吗?其实这里我们是把n-1看成是一个盘子,对于n-1内部来说,只不过是在重复执行了前面这一套流程而已 ,而且不管有多少个盘子,移动的方式都是这一套流程的堆叠。所以只需要考虑两个盘子,并且按照两个盘子的移动方式就可以写出代码。当然是用递归的方法
#include<iostream> using namespace std; static long lCount; //起始柱 过渡柱 目标柱子 void move(int n, char x, char y, char z) { if (1 == n) { cout << "Times:" << ++lCount << " " << x << "->" << z << endl; } //注意这里代表的意思不是x柱子移动到z柱,而是起始柱移动到目标柱子 else if (n >= 2) { move(n - 1, x, z, y); //n-1移动到b柱 cout << "Times:" << ++lCount << " " << x << "->" << z << endl; //n移动到c柱 move(n - 1, y, x, z); //n-1移动到c柱 } else { printf("输入错误 "); return; } return; } int main() { int n = 0; printf("请输入层数 "); scanf("%d",&n); move(n, A, B, C); return 0; }
这里要注意: move()函数里面的参数x,y,z代表的意思是死的,不会随着盘子的移动而改变,就是说x参数的位置代表的意思是起始驻,y参数的位置代表的是过渡柱,z参数的位置代表的是目标柱。比如n-1移动到c柱,a是过渡柱,b是起始柱,c是目标柱。但是第一个参数代表的意思是起始柱,所以把起始柱填到对应位置,后面类似,所以是 move(n - 1, y, x, z);
PS:递归,最里面的先执行,顺序还是从最外面开始。
这里要注意,盘子太多的话程序运行的会很久,因为每个两个盘子都会分解到一个上面的整个流程
=========================================================================青蛙跳台阶问题:
一个青蛙一次能跳一阶或者两阶台阶,问跳n阶台阶有几种跳法。
青蛙跳一阶台阶的跳法有 跳1阶 一种,跳两阶台阶有 跳1阶,再跳1阶,或者直接跳2阶台阶的两种跳法。因为第三阶台阶是一阶台阶和二阶台阶加起来的,会发现跳第三阶台阶的跳法是 跳一阶和跳两阶的跳法之和。
那么对于n来说 跳n阶就是跳n-1阶和n-2阶之和,是个斐波那契数列,由此就可以写出代码。
#include<iostream> //青蛙跳N节 台阶的方法 是 n-1 种方法加上 n-2 种方法 //所以这是个递归问题 跳一节 台阶 1 跳两节台阶 1,1 和 2; int jump(int n) { if (1 == n) return 1; else if (2 == n) return 2; else return jump(n - 1) + jump(n - 2); } int main() { int a = 0; printf("请输入要跳的台阶 "); scanf_s("%d",&a); printf("一共有%d种方法 ", jump(a)); return 0; }