汉诺塔是经典的递归问题,也有非递归解法,此处只讨论递归解法


1、游戏描述如下:

        A、B、C 三个桌子,其中A桌子上放了几个大小不同的盘子,盘子的排列顺序为: 从上到下,依次从小到大递增;现要求把这些盘子从 A 桌子上移动到 C 桌子上,盘子移动时有一点要求:每次移动必须保证三张桌子上大盘子在下、小盘子在上;



2、游戏步骤:

        1)当 A上有1个盘子时,只需要将A上的盘子移至C

        wKioL1Zaz9PysXbKAAA0MUh8bHI924.png


        2)当A上有2个盘子时,将A的1号盘子移动至B,再将A的2号盘子移至C,最后将B上的1号盘子移至C

        wKioL1Za0rPBiq0QAAB9VKLTWq0973.png

        3)当A上有3个盘子时,先借助C将1、2号盘子从A移至B,然后将3号盘子移动到C,最后借助A将B上的1、2号盘移至C

        wKiom1Za1i7z0x_pAAD0mcf0Q3Q377.png


        4)综上可知:当A上有N(N>1)个盘子时,先借助C将A上1至n-1号盘子(共n-1个)移至B,再将A上的n号盘子移至C,最后借助A将B上的n-1个盘子移至C盘。



3、算法描述

        美国一位学者发现了一种简单的算法,只需要轮流两步操作就能实现:

        首先把三个桌子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在桌子A上,根据圆盘的数量确定桌子的排放顺序:

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

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

        (3)接着,把另外两个桌子上可以移动的圆盘移动到新的桌子上。即把非空桌子上的圆盘移动到空桌子上,当两根桌子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,但是可实施的行动是唯一的。

        (4)反复进行(2)(3)操作,最后就能按规定完成汉诺塔的移动。



4、Python代码实现

#!/usr/bin/env python
# _*_ coding:utf-8 _*_


def input_n():
    
    while True:
        n = raw_input('请输入A上的盘子个数:')
        try:
            n = int(n)
            if n < 1:
              print '请输入大于0的整数!'
            else:
              break
        except Exception, e:
            print '请不要随意输入字符!'
        
    return n  

def move_info(n, from_table, to_table):
    
    step_info = '将%s号盘:%s ----> %s' % (n, from_table, to_table)
    return step_info
    
def recursion_hano(n, a, b, c, step_info_list = []):
    
    if n == 1:  # 当n=1时,直接将盘子移动至目的桌,递归终止条件
        step_info_list.append(move_info(1, a, c))
        
    else:
        recursion_hano(n-1, a, c, b)  # 先借助C将A上n-1个盘子移至B
        step_info_list.append(move_info(n, a, c))  # 将A最后一个盘子移动到C
        recursion_hano(n-1, b, a, c)  # 借助A将B上的n-1个盘子移至C
    
    return step_info_list
    
def main():
    
    n = input_n()  
    step_info_list = recursion_hano(n,'A', 'B', 'C')
    for i,k in enumerate(step_info_list):
        print '第%s步:%s' % (i+1, k)
    

if __name__ == '__main__':
    main()


5、其他

        当盘子为N时,移动次数为 2^N - 1