问题简介
汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。问应该如何操作?
逐步分析
当只有一个盘子时
这是最简单的情况:只需将1号盘子从X塔移动到Z塔就OK
于是我们可以写出如下的函数,来模拟完成这个过程。假设盘子是用1,2,3...按照大小编码代表的,而塔则是用一个字符char表示的。
//将编号为 number 的盘子从 from 塔座移到 to 塔座 void move(int number , char from , char to){ std::cout<<"move dish "<<number<<": " <<from<<"--->"<<to
<<std::endl; }
有两个盘子时
有2个盘子,目标是:将X塔上的盘子借助Y移动到Z盘子上。
特别的,为了好描述,我把X塔叫做 源塔,因为盘子起初在这个塔上,把Y塔叫做辅助塔,因为Y塔只是起个过渡作用。把Z盘叫做目标塔,最后所以的盘子都在这个塔上。
我们可以写出伪代码
move(1,X,Y); move(2,X,Z); move(1,Y,Z);
有三个盘子时
在盘子数大于2的时候,无论有多少个盘子,我们眼里只有2个盘子:即最底层的最大的盘子,和它上面的所有盘子组和形成的一个盘,我们可以把它看做是2.5号盘。
这样考虑的好处是:无论有多少盘子,都可以用2个盘子的思路去做。简化了思路。
因此,步骤是:
1、将2.5号盘借助Z塔移动到Y塔上。注意,处理这步操作时,X是源塔,Z是辅助塔,Y是目标塔
2、将3盘移动到Z塔上,
3、将2.5盘借助X塔移动到Z塔上。注意,处理这步 操作时,Y是源塔,X是辅助塔,Z是目标塔
/** * * 将n个盘子从塔座x上借助塔座y移动到塔座z上 */ void hanoi(int n , char x , char y, char z) { /** | | | | | | | | | _________ x y z */ if( n == 1){ move(1,x,z); } else{ hanoi(n-1,x,z,y); //将最大盘上面的(组合盘2.5号)盘从x塔借助z移动到y上 move(n,x,z); //将最大盘从x塔移动到z塔 hanoi(n-1,y,x,z); //将组合盘2.5号盘从y塔借助x移动到z上 } }
完整代码
#include<iostream> //将编号为 number 的盘子从 from塔座移到 to 塔座 void move(int number , char from , char to){ std::cout<<"move dish "<<number<<": " <<from<<"--->"<<to<<std::endl; } /** * * 将n个盘子从塔座x上借助塔座y移动到塔座z上 */ void hanoi(int n , char x , char y, char z) { /** | | | | | | | | | _________ x y z */ if( n == 1){ move(1,x,z); } else{ hanoi(n-1,x,z,y); //将最大盘上面的(组合盘2.5号)盘从x塔借助z移动到y上 move(n,x,z); //将最大盘从x塔移动到z塔 hanoi(n-1,y,x,z); //将组合盘2.5号盘从y塔借助x移动到z上 } } int main() { hanoi(3,'X','Y','Z'); return 0; }