汉诺塔的非递归实现

原题:https://pintia.cn/problem-sets/15/problems/821
汉诺塔的实现对于与我这种菜鸟来说第一时间都是想到递归,而且通过了。不过我看了一下非递归的思路:
汉诺塔的非递归算法描述如下:

首先容易证明,当盘子的个数为n时,移动的次数应等于2^n - 1。

一位美国学者发现一种出人意料的方法,只要轮流进行两步操作就可以了。

首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上。

根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;

若n为奇数,按顺时针方向依次摆放 A C B。

(1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;

若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。

(2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。

即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘

这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

(3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。
然后我自己实现了一下。(由于代码没保存只能口述了)
由于汉诺塔的规则所以肯定要使用栈来实现
char s[4] = { ‘q’,‘a’,‘b’,‘c’ };
std::stack a[4];
由于总是在1,2,3内循环所以这样定义。由于要不停的进行插入和删除而且行动次数是固定的所以我定义了一个iCount=1;然后根据iCount来执行,但是我遇到的第一个问题就是如何反复循环取到1,2,3因为iCount对三取余也只是0,1,2然后还有就是如何有规律的进行步骤1和2。这里面遇到的问题太多了,我就把每一个步骤都讨论了一遍,尽管完成了但是也是复杂的不行。然后我看了一下别人的代码,真的是妙。
#include
#include
char s[4] = { ‘q’,‘a’,‘b’,‘c’ };
std::stack a[4];
bool move(int before, int after) {
if (a[before].empty())
return false;
if (!a[after].empty())
if ((a[after].top() - a[before].top()) < 0)
return false;
a[after].push(a[before].top());
a[before].pop();
printf("%c -> %c\n", s[before], s[after]);//faster than cout
return true;
}
int main() {
int N, count = 0;
std::cin >> N;
for (int i = 0; i < N; i++)
a[1].push(N - i);
if (N % 2 == 1) {
s[2] = ‘c’; s[3] = ‘b’;
}
while (++count) {
move((count - 1) % 3 + 1, (count) % 3 + 1);
if (!move((count - 1) % 3 + 1, (count + 1) % 3 + 1)&&!move((count + 1) % 3 + 1, (count - 1) % 3 + 1))
break;
}
}
————————————————
版权声明:本文为CSDN博主「韩旭051」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shiliang97/article/details/100150223
妙就在于他找出了一般的规律,其实所有的步骤都要归结到出栈,插入,打印。这个代码我刚看的时候还是不懂然后在草稿纸上研究了一番,确实很有技巧。一时间也说不出技巧在哪,读者可以去研究一下。

你可能感兴趣的:(算法)