汉诺塔问题(Hanoi)
汉诺塔问题,一直是递归问题的典范。同时这个问题也随着时间的发展而推陈出新,一步步考验着人类的智商。在这里做一些总结,但因笔者才疏学浅。如有不足希望指正。
最基本的问题
题目描述:
汉诺塔由编号为1到n大小不同的圆盘和三根柱子a,b,c组成。开始时,这n个圆盘由大到小依次套在a柱上,如图所示。要求把a柱上n个圆盘按下述规则移到c柱上:
- 一次只能移一个圆盘,它必须位于某个柱子的顶部;
- 圆盘只能在三个柱上存放;
- 任何时刻不允许大盘压小盘。
将这n个盘子从a柱移动到c柱上,最少需要移动多少次?
Solution:
直接递归就可以了,假设最初在a号柱子上有N个盘子,并且由上到下半径依次增大,那么我们可以把上面的n-1个盘子看成一个整体,而我们现在要做的就是把n-1个盘子从a移动到b,然后把最大的盘子由a移动到c再把那n-1个盘子由b移动到c。
其实随着思考的深入,你会发现,其实在 汉诺塔 问题中,我们其实想要实现的就是把n个盘子从一根柱子移动到另一个柱子上,而我们只不过不得不借助另一个柱子来帮助实现而已。
所以,现在我们的原问题就可以转化为一个较简单的子问题,也就是把剩下的n-1个盘子,由一根柱子,转移到另根柱子就可以了。
现在我们可以无限的递归下去,直到只剩下一个盘子,那么答案显然就是1了。这样我们再一点点的回溯回去,就可以得到答案了。
Code:
#include<stdio.h>
void hanoi(int n,char a,char b,char c)
{
if(n==1)
{
printf("%d:%c->%c\n",1,a,c);
}
else
{
hanoi(n-1,a,c,b);//用 b 柱作为协助过度,将 a 上的(n-1)片移到 c 上
printf("%d:%c->%c\n",n,a,c);
hanoi(n-1,b,a,c);//用 c 柱作为协助过度,将 b 上的(n-1)片移到 a 上
}
}
int main()
{
int n;
scanf("%d",&n);
hanoi(n,'A','B','C');
return 0;
}
简单的变形
- 原问题中,我们是n个盘子,移动到三根柱子上,上面的代码是用了递归的思想进行了路径的输出。
当我们想要知道方案数的时候,不妨可以打表看一下:
n | 方案数 |
---|---|
3 | 7 |
4 | 15 |
5 | 31 |
6 | 63 |
… | … |
这个时候好像就可以知道好像可以递推出n个盘子的公式: