Python: 每日一题之汉诺塔(递归、栈)

题目描述

汉诺塔是一个古老的数学问题: 有三根杆子 A,B,C。A 杆上有 N 个 (N>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:

  • 每次只能移动一个圆盘
  • 大盘不能叠在小盘上面

提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。问:如何移?最少要移动多少次?

输入描述

一行,包含 2 个正整数,一个是 N,表示要移动的盘子数;一个是 M,表示最少移动步数的第 M 步。

输出描述

共 2 行。

第一行输出格式为:#No: a->b,表示第 M 步骤具体移动方法,其中 No 表示第 M 步移动的盘子的编号(N个盘子从上到下依次编号为 1 到 n),表示第M步是将 No 号盘子从 a 杆移动到 b 杆(a和 b 的取值均为 {A、B、C})。

第 2 行输出一个整数,表示最少移动步数。

样例">样例">输入输出样例

示例 1

输入

3 2

输出

#2: A->B
7

 思考:

抽象为数学问题:
  如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数

解:(1)n == 1

             第1次  1号盘  A---->C       sum = 1 次

       (2)  n == 2

             第1次  1号盘  A---->B

             第2次  2号盘  A---->C

             第3次  1号盘  B---->C        sum = 3 次

  (3)n == 3

        第1次  1号盘  A---->C

        第2次  2号盘  A---->B

        第3次  1号盘  C---->B

        第4次  3号盘  A---->C

        第5次  1号盘  B---->A

        第6次  2号盘  B---->C

        第7次  1号盘  A---->C        sum = 7 次

不难发现规律:1个圆盘的次数 2的1次方减1

       2个圆盘的次数 2的2次方减1

                         3个圆盘的次数 2的3次方减1

                         。  。   。    。   。 

                         n个圆盘的次数 2的n次方减1

 故:移动次数为:2^n - 1

算法分析(递归算法):
       我们在利用计算机求汉诺塔问题时,必不可少的一步是对整个实现求解进行算法分析。到目前为止,求解汉诺塔问题最简单的算法还是同过递归来求。

       实现这个算法可以简单分为三个步骤:

       (把n-1个盘子看做一个整体,把第n个盘子看作一个整体)

    (1)     把n-1个盘子由A 移到 B;

    (2)     把第n个盘子由 A移到 C;

    (3)     把n-1个盘子由B 移到 C;

从这里入手,在加上上面数学问题解法的分析,我们不难发现,移到的步数必定为奇数步:

    (1)中间的一步是把最大的一个盘子由A移到C上去;

    (2)中间一步之上可以看成把A上n-1个盘子通过借助辅助塔(C塔)移到了B上,

    (3)中间一步之下可以看成把B上n-1个盘子通过借助辅助塔(A塔)移到了C上;
 

参考代码: 

1、递归实现

n, m = map(int, input().split()) # n 移动的盘子数,m 最少移动步数
sum = 0
def hanoi(x, y, z, n):
    global sum           #global声明变量sum为全局变量。
    #当只有一个圆盘时
    if (n == 1):         #如果只有一个盘子直接拿到C
        sum += 1         #移动次数加一
        if sum == m:   #若 m=0 直接将A-->C
            print(f"#{n}: {x}->{z}")
    #当圆盘数大于一时
    else:
        hanoi(x, z, y, n-1)#将n-1个盘子从A通过C移动到B
        sum += 1
        if sum == m:
            print(f"#{n}: {x}->{z}")
        hanoi(y, x, z, n-1)#调用自身将剩下的n-1个盘子从B通过A移动到C

hanoi("A", "B", "C", n)
print(sum)

global语句的用法

语法:
声明此变量为全局变量。

用法:
global [变量名]

注意:
引用全局变量时,不需要global声明;但是后面使用或者修改这个全局变量的时候,需要global声明

 实例

num = 1
def fun():
     global num
     num = 2
     print(num)

fun()
print(num)

#输出结果为	2
#		 	2

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
汉诺塔问题是一个经典的递归问题,其目标是将所有圆盘从一个标杆移动到另一个标杆,同时满足每次只能移动一个盘子,并且较大的盘子不能放在较小的盘子上面。下面是一个用Python编写的汉诺塔递归算法的示例代码: ```python def move(n, A, B, C): if n == 1: print(A, "->", C) else: move(n-1, A, C, B) print(A, "->", C) move(n-1, B, A, C) n = int(input("请输入盘数:")) print("具体走法步骤如下:") move(n, "A", "B", "C") ``` 这段代码中,`move`函数接受四个参数,`n`表示当前需要移动的盘子数量,`A`、`B`、`C`分别表示三个标杆。当`n`等于1时,直接将盘子从A移动到C;否则,先将n-1个盘子从A移动到B,然后将最后一个盘子从A移动到C,最后再将n-1个盘子从B移动到C。通过递归调用,实现了整个汉诺塔的移动过程。 请注意,这段代码中使用了全局变量`i`来记录移动的步数,所以在使用时需要将全局变量`i`初始化为1。另外,这段代码中的输出语句使用了箭头符号`->`来表示移动的方向。 希望这个示例代码能够帮助你理解和实现汉诺塔递归算法。 #### 引用[.reference_title] - *1* *3* [汉诺塔递归算法Python编程)](https://blog.csdn.net/weixin_44263764/article/details/97390068)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [汉诺塔——python递归](https://blog.csdn.net/New_Teen/article/details/123564145)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的敲码工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值