理解 Hanoi 汉诺塔非递归算法

汉诺塔介绍:

汉诺塔(港台:河内塔)是根据一个传说形成的数学问题:

最早发明这个问题的人是法国数学家爱德华·卢卡斯

传说越南河内某间寺院有三根银棒,上串 64 个金盘。寺院里的僧侣依照一个古老的预言,以上述规则移动这些盘子;预言说当这些盘子移动完毕,世界就会灭亡。这个传说叫做梵天寺之塔问题(Tower of Brahma puzzle)。但不知道是卢卡斯自创的这个传说,还是他受他人启发。

若传说属实,僧侣们需要 \(2^{64}-1\)步才能完成这个任务;若他们每秒可完成一个盘子的移动,就需要5849 亿年才能完成。整个宇宙现在也不过 137 亿年

这个传说有若干变体:寺院换成修道院、僧侣换成修士等等。寺院的地点众说纷纭,其中一说是位于越南河内,所以被命名为“河内塔”。另外亦有“金盘是创世时所造”、“僧侣们每天移动一盘”之类的背景设定。

介绍完汉诺塔背景以后开始解决下非递归思路

汉诺塔的非递归算法描述如下:

首先容易证明,当盘子的个数为n时,

假设有 n 片,移动最少次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。

此后不难证明 n 片时移动的次数应等于2\(^n - 1\)

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

我们假设现在最小的圆盘在a柱子上,柱子为a,b,c

第一步:将最小圆盘移动到下一个柱子上,也就是b

第二步:对a柱子和c柱子进行顶上最小的元素进行判断,把小一点的那个圆盘移动到大一点的那个圆盘(有空则摞在空柱子上)。

反复进行前面两步操作,最后就能按规定完成汉诺塔的移动。

注意:这样得到的最后的答案不一定是摞在c上,如果N是偶数将摞在b上,所以如果N是偶数我们就令第二个柱子为c,第三个柱子为b,这样就一定最后是摞在c上的。

汉诺塔非递归算法实现

#include<iostream>
#include<stack>
using namespace std;
char s[3] = { 'a', 'b', 'c' };//代表3个柱子
stack<int> a[3];
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 0;
    }
    a[after].push(a[before].top());
    a[before].pop();
    printf("%c -> %c\n", s[before], s[after]);
    return true;
}
int main()
{
    int N, count = 0;
    cin >> N;
    for (int i = 0; i < N; i++)
        a[0].push(N - i);
    if (N % 2 == 1)
    {
        s[1] = 'c';
        s[2] = 'b';
    }
    while (++count){
        move((count - 1) % 3, count % 3);
        if (!move((count - 1) % 3, (count + 1) % 3))
        if (!move((count + 1) % 3, (count - 1) % 3))
            break;
    }
    return 0;
}

题目实战链接 PTA7-17

查找资料的时候发现N皇后问题与汉诺塔的非递归有类似又不同的思想,这几天赶快安排下学习N皇后(偷懒好久了2333)

猜你喜欢

转载自www.cnblogs.com/RioTian/p/12684372.html