问题描述:
有A,B,C三根柱子,A上有一叠自上到下是从小到大的盘子,需要将其全部移到C上,要求每次只能移一个盘子,且规定大盘子要在小盘子下面,问当有N个盘子的时候,最少移动多少次?
刚开始一直不知道N>=3的时候为什么是那样移,别人写的递归方程为什么那样写?看了好多博文加上自己的思路才明白!
首先我们要明白,A最下面最大的盘子一定要移到C柱子最底下!然后我们再来讨论:
当N=1时,很简单,直接从A->C;
当N=2时,A->B,A->C(A最大的盘子移到C),B->C,OK!
当N=3时,我们将三个盘子的上面两个捆绑,就又相当于是N=2的情况;
将捆绑的两个盘子从A移到B,再将底下最大的盘子从A移到C,再将捆绑的两个盘子从B移至C,OK!
然后我们考虑的问题就是上面两个捆绑的盘子是怎么A->B,历史总是惊人的相似!此时我们会发现这是的B充当着当N=2时C的角色,所以我们很容易推出应该是A->C,A->B,C->B;同理,两个捆绑的盘子是怎么B->C,不过是将(N=2时的情况)A换成B,于是B->A,B->C,A->C;
综上,N=3时,盘子应该这样移:A->C,A->B,C->B,A->C(最大的盘子从A移到C),B->A,B->C,A->C,一共移7次;
。。。以此类推,我们解决汉诺塔问题就要分三步骤:
1.将A上面n-1个盘子移到B;
2.将A底下最大的盘子移到C;
3.将B上n-1个盘子移到C;大功告成
用递归解决这个问题,代码如下:
#include<iostream>
using namespace std;
void move(char x,char z){
cout<<x<<" "<<"to"<<" "<<z<<endl;
}
void hannot(int n,char x,char y,char z){//n指A柱子上的盘子总数,x,y,z指三个柱子
if(n==1){
move(x,z);
}
else{
hannot(n-1,x,z,y); //表示盘子从A移到B
move(x,z); //表示最大盘子从A移到C
hannot(n-1,y,x,z); //表示盘子从B移到C
}
}
int main(){
int n;
cin>>n;
hannot(n,'A','B','C');
return 0;
}
感觉看递归代码,绕进去很难出来,但还是要掌握什么时候可以使用它解决问题:确定问题的结束条件以及如何让问题规模缩小。
欢迎大家批评指正拓展!