问题描述:古代有一座梵塔,塔内有3个座A、B、C。开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上。有一个老和尚想把这64个盘子从A座移到C座,但每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求编程打印出移动的步骤。
程序设计分析:将n个盘子从A座移到C座可以分解为以下3个步骤。
- 将A座上n-1个盘借助C座先移到B座上。
- 把A座上剩下的一个盘移到C座上。
- 将n-1个盘从B座借助于A座移到C座上。
假设现在A座上有3个盘子,从上到下分别编号为1、2、3。如果想将A座上3个盘子移到C座上,可以分解为以下3步。
(1)将A座上2个盘子移到B座上(借助C)。(1号、2号)
(2)将A座上1个盘子移到C座上。(3号)
(3)将B座上2个盘子移到C座上(借助A)。(1号、2号)
第(1)步又可以用递归方法分解为
1.1将A上1个盘子从A移到C。(1号)
1.2将A上1个盘子从A移到B。(2号)
1.3将C上1个盘子从C移到B。(1号)
第(3)步可以分解为
3.1将B上1个盘子从B移到A上。(1号)
3.2将B上1个盘子从B移到C上。(2号)
3.3将A上1个盘子从A移到C上。(1号)
将以上综合起来,可得到移动3个盘子的步骤为:
A—>C,A—>B,C—>B,A—>C,B—>A,B—>C,A—>C
总共是2的3次方后减1,即7步。
#include<stdio.h>
#include<math.h>
void main()
{
void hanoi(int n, char one, char two, char three); /*对hanoi函数的声明*/
int m,n; /*定义整型变量m(盘子数),n(移动步数)*/
printf("请输入盘子数:");
scanf_s("%d", &m);
printf("移动%d个盘子的步骤是:\n", m);
hanoi(m, 'A', 'B', 'C');
n = pow(2, m) - 1; /*计算全过程总共花费的步骤数*/
printf("总共移动了%d次", n);
}
void hanoi(int n, char one, char two, char three)
{
void move(char x, char y); /*对move函数的声明*/
if (n == 1) move(one, three);
else {
hanoi(n - 1, one, three, two);
move(one, three);
hanoi(n - 1, two, one, three); /*在盘子移动的过程中,定义了直接移动的move函数和通过中转柱间接移动的hanoi函数,再通过对全过程进行递归使问题简单化*/
}
}
void move(char x, char y) /*定义move函数*/
{
printf("%c->%c\n", x, y);
}
说明:汉诺塔问题可通过二进制反映出来。采用二进制的计数方式,从右往左看,当第一位发生改变时,移动1号盘,第二位发生改变时,移动2号盘,第三位发生改变时,移动3号盘。
注意:本处的发生改变指的是在十进制数+1的情况下,二进制中的某一位实现了从0—>1的转化。