问题描述:将 A 座上的 n 个盘子借助 B 座,移到 C 座上,并且每次移动只能大盘在下,小盘在上
如下图:
该问题我们用递归来求解
请务必注意我们是反向思考的,步骤便可以拆分为
第一步:先将 A 座上的 n - 1 个盘子借助于 C 座移到 B座
那这 n - 1 个盘子是怎么移动的呢?
注意我们是反向思考的,所以我们暂时不考虑,先假设他已经移动过去了
第二步:此时 A 座上只剩下第 n 个盘子,将他直接移到 C 座
注意:这是在第一步已经完成的情况下
第三步:最后将 B 座上的 n - 1 个盘子借助于 A 座 移到 C 座
此时汉诺塔的问题便解决了
现在我们考虑 n - 1个盘子是怎么移动的呢?
仔细思考可以发现,和上述步骤的思考方式是一样的,需要注意几点
- 当前需要移动的盘子数量
- 当前盘子的起始位置,以及需要移动的位置,剩下的位置就是需要借助的位置
综上:需要移动 n 个盘子时我们转化为先移动 n - 1 个盘子,然后我们又可以转化为移动 n - 2 个盘子,依次类推,直到只剩下一个盘子时,我们可以直接移动,就不需要在转化了
如果理解了我们便可以根据步骤写代码了,在这我把他放在函数里实现
//第一个参数表示盘子的数量
//第二个参数表示起始座
//第三个参数表示借助座
//第四个参数表示目标座
void hanoi(int m, char one, char two, char three)
{
//如果只剩下一个盘子,就不需要拆分了
if (m == 1)
{
printf("%c--->%c\n", one, three);
return;
}
//注意:下面的注释一定要根据这条来理解
//在当前函数中我们的起始座是 one,借助座是 two,目标座是 three
//这里移动 m - 1 个盘子,我们需要先完成第一步,将他移动到 two(借助座),
hanoi(m - 1, one, three, two);
//这里完成第二步
printf("%c--->%c\n", one, three);
//这里也是移动 m - 1 个盘子,完成第三步
//注意:第一步我们已经将 m - 1 个盘子移动到了 two(借助座)上
//所以此时是从 two(借助座) 移到 three(目标座)
hanoi(m - 1,two, one, three);
}
函数的返回类型虽然为 void 但是也可以用 return,但 return 后面不能跟值
最后是运行结果和代码
#include<stdio.h>
void hanoi(int m, char one, char two, char three)
{
if (m == 1)
{
printf("%c--->%c\n", one, three);
return;
}
hanoi(m - 1, one, three, two);
printf("%c--->%c\n", one, three);
hanoi(m - 1, two, one, three);
}
int main()
{
hanoi(3, 'A', 'B', 'C');
return 0;
}