问题描述:
古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个和尚想把这64个盘子从A座移动到C座,但每次只能允许移动一个盘子,并且在移动的过程中,3个座上的盘子始终保持大盘在下小盘在上。在移动过程中可以利用B座,要求移动的步骤。输入为A座盘子的数量,输出为盘子的移动方式。
样例输入:
4
样例输出:
1:A->B
2:A->C
1:B->C
3:A->B
1:C->A
2:C->B
1:A->B
4:A->C
1:B->C
2:B->A
1:C->A
3:B->C
1:A->B
2:A->C
1:B->C
问题分析及解决:
这是一道经典的递归算法题。我们假设当前A座有n个盘子(n>=1),如何进行移动盘子。
首先分别讨论盘子数比较少的情形:
1)当n=1时,
直接将A座唯一的盘子移动到C座即可。
2)当n=2时,
先将A座的小盘子移动到B,再将A座稍微大一点的盘子移动到C,最后将小盘子移动到C上。
此时,我们发现语言描述移动盘子已经显得有点费力了,不妨将初始时,盘子的序号从上向下以此排序为1,2,3...n
移动盘子可以写为:
1:A->B,意思为,将序号为1的盘子从A移动到B,这样的描述方式更为清晰明了
3)当n=3时,
1:A->C
2:A->B
1:C->B
3:A->C
1:B->A
2:B->C
1:A->C
当n>3时,盘子的移动变得越来越复杂了,我们需要从复杂的过程中找到规律。
不难发现,如果我们想把所有的盘子从A移动到C,那么,我们肯定是要先把n-1个盘子以C为过度从A移动到B,然后将最后一个盘子移动到C,最后再将B座上的n-1个盘子以A为过度从B移动到C,便可以完成整个的操作过程。那么,n-1个盘子的移动过程也是同样的套路,从n-2个盘子的移动开始,依次类推。从而可以写出相关的递归算法代码。
代码
#include <iostream>
using namespace std;
//n为A座初始的个数,Order_n为自上而下的序号,Hanoi的功能是将A上n个盘子移动到C上,B作为中间的辅助
void Hanoi(int n, char A, char B, char C,int Order_n)
{
if (n == 1)
{
cout << Order_n << ":" << A << "->" << C << endl;//若A座只有一个,则直接将该盘子移动到C座上
return;
}
//当n不为0时,主要有3个操作
Hanoi(n - 1, A, C, B, Order_n);//先将n-1个盘子从A移动到B
cout << Order_n + n - 1 << ":" << A << "->" << C << endl;//将最后一个标号的盘子从A移动到C
Hanoi(n - 1, B, A, C, Order_n);//最后再将B上n-1个盘子从B移动到C
}
void main()
{
char A, B, C;
int n;
A = 'A';
B = 'B';
C = 'C';
cin >> n ;
Hanoi(n, A, B, C, 1);//这里入参多了A,B,C,可以自行定义座子的名称
}