什么是汉诺塔
是根据一个传说形成的数学问题:
有三根杆子A,B,C。A杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
- 每次只能移动一个圆盘;
- 大盘不能叠在小盘上面。
提示:可将圆盘临时置于 B 杆,也可将从 A 杆移出的圆盘重新移回 A 杆,但都必须遵循上述两条规则。
三个圆盘时的解法
四个圆盘时的解法
那么五个圆盘时的解法呢
现在我们规定 左边柱子编号为A,中间柱子编号为B,右边编号为C
A是初始位置,C是目标位置
那么5个圆盘的解法就是将上面四个圆盘移动到B 再将第5个圆盘移动到C
再将那四个圆盘从B移动到C就完成了
N个圆盘的解法
简单来说就是三步
- 将n-1个圆盘从A移至B
- 将第n个圆盘移至C
- 再将n-1个圆盘从B移至C
递归概念的引出
现在我们提出一个简单的汉诺塔问题:
给定N个圆盘的汉诺塔 求解需要移动多少次才能从初始状态抵达目标状态?
定义一个函数K K(N)表示N个圆盘的汉诺塔的移动次数
根据之前的思考 我们可以得到这样一个式子
K(N)=K(N-1)+1+K(N-1)=2*K(N-1)+1
那么求解K(N)即求解K(N-1)
而我们并不知道K(N-1)
但我们知道K(1)=1
那么我们如何将K(N),K(N-1)和K(1)联系起来
没错就是上面那个公式
其实我们可以直接通过上面的公式得知K(N)=2^N-1
这其实就是一个递归表达式
递归表达有着下面几个特点:
- 原本问题会在处理后,问题规模会变小(K(N)经过处理后变成K(N-1))
- 有边界(不能再小的问题,K(1)不用再变小)
int solve(int Size)//在这个问题中 B和C是不用区别的
{
if(Size==1)
return 1;
return 2*solve(Size-1)+1;
}
递归的基本模式
- 我们已经完成了吗?如果完成了,返回结果。如果没有这样的终止条件,递归将会永远地继续下去。
- 如果没有,则简化问题,解决较容易的问题,并将结果组装成原始问题的解决办法。然后返回该解决办法。
汉诺塔问题(正常版本)
将移动过程按照
N from A to C(N表示盘子的编号,A,C表示柱子的编号)
的格式输出
void hannoi (int n, char from, char buffer, char to)
{
if (n == 0)
return;
hannoi (n - 1, from, to, buffer);
cout << "Move disk " << n << " from " << from << " to " << to << endl;
hannoi (n - 1, buffer, from, to);
}
int main()
{
int n;
cin >> n;
hannoi (n, 'A', 'B', 'C');
return 0;
}