汉诺塔问题与二进制

汉诺塔问题从很久很久以前就被当做益智游戏来供我们青少年进行智力的训练,当然在我们的成长过程中也起到了一定的作用。但是,以我们当时的思维来说,我们只知道这个问题如何能够解决,并没有去细究其为什么这么做,这个问题背后包含的原理是什么。那么,现在从为什么这样解决的角度来解决汉诺塔问题。

  • 汉诺塔问题(Hanoi Tower)

汉诺塔问题的组成部分有若干个大小各不相同的圆盘(N),三个可以放置圆盘的柱子。

三个柱子可以分别标记为A、B、C。起始N个大小各不相同的圆盘按从大到小,从下到上的顺序以此排列在A柱上。每次只能动一个圆盘,且较大的圆盘只能在较小的圆盘下面。问如何移动,可以将A柱的所有圆盘移动至C柱。(在这里,我们暂时不考虑最优解法)

                                 汉诺塔问题与二进制_第1张图片

  • 二进制(binary system)

二进制各位都再熟悉不过了,就是逢二进一。二进制的10表示2,100表示4。

  • 汉诺塔问题与二进制

为了方便解释,首先我们从上到下,由小到大给A柱上的圆盘进行编一个号码,分别为0、1、2、3、4……我们先看一看汉诺塔问题的基础情况。当且仅当有两个圆盘的时候,即0号圆盘和1号圆盘时。我们第一步先得将0号圆盘移动至B柱,然后将1号圆盘移动至C柱,再将B柱上的0号圆盘移动至C柱上,即完成了汉诺塔问题的基础情况。

现在我们加大难度,将圆盘增加至三个,即0、1、2​​​​​​。我们第一步要做的仍然是将0号圆盘移动至B柱,将1号圆盘移动至C柱,然后将0号圆盘移动至A柱,再将C柱上的1号圆盘移动至B柱,再将0号圆盘移动至B柱。此时的情况是A柱上有2号圆盘和0号圆盘,B柱上有1号圆盘,C柱为空。将0号圆盘从A柱移动至B柱,将2号圆盘移动至C柱,将0号圆盘移动至A柱,1号圆盘移动至C柱,将0盘再移动到C柱,到此就大功告成了。也许,这样你会被我这样的描述冲昏头脑,因此,不如放上一张图片来表述其过程。

聪明的你先通过这个动画来看一看,其与二进制有何内在联系。

不错的,我们可以将0号圆盘的移动认为是二进制中的个位计数,1号圆盘认为是二进制中的十位计数,2号圆盘认为是二进制中的百位计数。即每动在个位上加一,就可以认为移动了一次0号盘,每在十位上加一就可以认为是移动了一次1号盘,每在百位上加一个一,就可以认为是移动了一次2号盘。而我上述所描述的过程就是 000 001 010 011 100 101 110 111。那么就是分别移动了对应的圆盘。这样的解法是不是很巧妙呢?

  • 递归

​​​​​​​以上,可以说是很清晰的了解到了汉诺塔问题的解法。在计算机中,汉诺塔问题的解法为递归解法。把N个圆盘移到另外一根柱子上需要先把底盘上方的N-1个圆盘进行移动,而移动这N-1个又需要先移动更上面的N-2个,如此循环至最开始的只有一个圆盘的情况。

void hanoi(n, from, to, tmp) {
    if (n == 0) {
        return;
    }
    
    if (n == 1) {
        moveBottom(n, from, to);
        return;
    }
    
    hanoi(n-1, from, tmp, to);
    moveBottom(n, from, to);
    hanoi(n-1, tmp, to, from);
}

 

由于具体是想说明二进制的解法,重点并非为递归的解法,故只给出参考伪代码。最后和大家分享一个很不错的视频,其解释也相当的到位:https://www.bilibili.com/video/av7398130

你可能感兴趣的:(汉诺塔问题与二进制)