C++汉诺塔问题描述和解决方案

汉诺塔问题

问题描述

现在有三个柱子,编号A,B,C.现在有n个圆盘,规定圆盘只能把小圆盘放在大圆盘上(不能大圆盘放在小圆盘上),初始n个圆盘全部在A柱上,现在要把A的圆盘全部移动在C上

请你返回你的移动步骤,使得移动次数最少

打开百度APP看高清图片

思路求解

这道题我们可能一时之间难以实现,我们可以把子问题给进行分解

试想:我们如果要把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个位置,重复此过程,即可把大问题分解

下来把我们的两个问题测试一下

 

 

 

 
posted @ 2022-02-22 17:49  冯丙见  阅读(206)  评论(0编辑  收藏  举报