常见递归问题
- 汉罗塔问题
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子(A,B,C),在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
规则:1、每次只能移动一个盘子
2、大盘子不能放在小盘子上面
问题:有n层黄金圆盘时 如何用递归演绎?并且需要多少次移动才能将其从A到C盘?
分析:
1.当n=1时,从A到C只需要 1 次移动
2.当n=2时,先将小的移动到B底层移动到C,在将小的从B移动到C,总共需要 3 次
3.当n=3时,同理,现将最上层移动到C,中间层移动到B,在C的最上层 移动到B,然后将A的底层移动到C 最后转化为最上层和中间层 从B移动到C,结束时就正好移动完,
此时发现在n=3中,总体思路是 将上两层移动通过借助C移动到B,然后将A的底层移动到C,再将B中的二层通过A移动到C,此时二层的移动了两次。
类比4,5,6一样的 都是前n-1层移动了两次,再移动一次底层
转换为递归模型:
1.涉及问题的规模 ,此处为黄金盘层数n
2.当规模发生变化时,解决问题方法不变,都是将上n-1层移动通过借助C移动到B,然后将第n层移动到C,再将B中的n-1层通过A移动到C,此时n-1层总共的移动了两次
大规模问题可以转换为小规模问题,n层的黄金盘 可以转换为n-1层的黄金盘移动两个和移动第n层
3.小规模问题有解:当n=1时 只需要移动1次
归纳:1、当n=1时,A柱子只有一个盘子,可以直接移到C上去
2、当n>=2时,将A柱子上n-1个盘子借助C柱子移到B上,将A最后一个盘子移到C上,最后将B柱子借助空A柱子移到C上。
代码:
void Hanoi(int n, char a, char b, char c)//a为原始柱,b为借助柱,c为目标柱 { if (n == 1) { Move(a, c);//只有一个盘子时直接移 } else { Hanoi(n - 1, a, c, b);//将A柱子上n-1个盘子借助C柱子移到B上 Move(a, c);//将A最后一个盘子移到C上 Hanoi(n - 1, b, a, c);//将B柱子借助空A柱子移到C上 } } void Move(char orin, char target) { cout << orin << "->" << target << endl; }
算法分析:
设盘子个数为n时,需要T(n)步,把A柱子n-1个盘子移到B柱子,需要T(n-1)步,A柱子最后一个盘子移到C柱子一步,B柱子上n-1个盘子移到C柱子上T(n-1)步。
得递推公式T(n)=2T(n-1)+1
所以汉诺塔问题的时间复杂度为O(2^n);