C++汉诺塔问题描述和解决方案
汉诺塔问题
问题描述
现在有三个柱子,编号A,B,C.现在有n个圆盘,规定圆盘只能把小圆盘放在大圆盘上(不能大圆盘放在小圆盘上),初始n个圆盘全部在A柱上,现在要把A的圆盘全部移动在C上
请你返回你的移动步骤,使得移动次数最少
思路求解
这道题我们可能一时之间难以实现,我们可以把子问题给进行分解
试想:我们如果要把2个圆盘挪动需要什么步骤?
把上面一个移动到中间
把最后一个移动到目标处
把中间的圆盘移动到目标处
既然这样,我们可以进行一下推广:
如果我们有n个圆盘的话:
把上面n-1个圆盘移动到中间
把最后一个圆盘移动到目标处
把中间的n-1个圆盘移动到目标处
就像这样:
然后对于上面n-1的圆盘,我们可以考虑从n-2到n-1重复调用此过程
这就是我们的最优解法了
所以我们的初始函数可能需要以下过程
对于过程中的两个函数,大家可以暂时把它们想成黑盒子,它们只执行了移动过程
因为我们的主过程是从A到C,所以我们的主函数是fromAToC(n)
至于我们中间涉及到的函数,我们可以仿照我们的思想,轻松给它补上
例如fromAtoB
依次类推,我们写出了六个函数相互依赖的解法
void hanoiTest2(int n) { fromAToC(n);//我们的主过程 } void fromAToB(int n) { if (n == 1) { cout << "1号:" << "A->B" << endl; return; } fromAToC(n - 1); cout << n << "号:" << "A->B" << endl; fromCToB(n - 1); } void fromAToC(int n) { if (n == 1) { cout << "1号:" << "A->C" << endl; return; } fromAToB(n - 1); cout << n << "号:" << "A->C" << endl; fromBToC(n - 1); } void fromBToC(int n) { if (n == 1) { cout << "1号:" << "B->C" << endl; return; } fromBToA(n - 1); cout << n << "号:" << "B->C" << endl; fromAToC(n - 1); } void fromBToA(int n) { if (n == 1) { cout << "1号:" << "B->A" << endl; return; } fromBToC(n - 1); cout << n << "号:" << "B->A" << endl; fromCToA(n - 1); } void fromCToA(int n) { if (n == 1) { cout << "1号:" << "C->A" << endl; return; } fromCToB(n - 1); cout << n << "号:" << "C->A" << endl; fromBToA(n - 1); } void fromCToB(int n) { if (n == 1) { cout << "1号:" << "C->B" << endl; return; } fromCToA(n - 1); cout << n << "号:" << "C->B" << endl; fromAToB(n - 1); }
我们如何把上面这个函数改成递归版本呢?
设我们的三个柱子分别为from,other,to
其中from代表圆盘刚开始的位置,to代表我们移动的目标位置,other代表另外的辅助位置
我们的目标是把from的所有圆盘移动到to
我们把上面函数这三个过程改一下即可
第一个过程,我们是先把上面的n-1个圆盘移动到辅助位置,方便我们最大的圆盘进行移动
所以我们的第一个过程针对上面n-1个圆盘,目标改成了other,利用to把它们移动到other
第二个过程,我们把最大的圆盘从from移动到to
第三个过程,我们需要归位,即把中间的圆盘从other移动到to,辅助位置是from
我们对于上面n-1个位置,重复此过程,即可把大问题分解
下来把我们的两个问题测试一下