汉诺塔递归;汉诺塔盘子的移动次数

解析:

'''
永远不要试图跟踪一个大型递归的过程!
要写出递归,关键就是找出递归的递归方程式:
也就是说,要完成的最后一步是什么,那么最后一步的前一步要做什么
又或者说,要完成这一步那么下一步该做什么
'''

# 汉诺塔的模拟递归过程:
# 有n个盘子,需要由a经过b移动到c:(n,a,b,c)
# 第一步、先把n-1个盘子由a经过c移动到b:(n-1,a,c,b)
# 第二步、把第n个盘子由a经过’b‘移动到c:(1,a,b,c),---只有一个盘子了当然不用在经过b移动到c了,这么写只是为了使结构一致方便写递归函数
# 第三步、把n-1个盘子由b经过a移动到c:(n-1,b,a,c)
# 最后递归就行了

代码:

def move(n,a,b,c):

    # 递归出口,如果只有一个盘子,直接把它移到c就行了,当然a和c只是参数,他们既可以是a也可以是b和c,但是:永远不要试图跟踪一个大型递归的过程!
    # 只需要认为他就是从a直接移动到c就行了
    if n==1:
        print(a,'-->',c)
    else:
        move(n-1,a,c,b) # 第一步、先把n-1个盘子由a经过c移动到b:(n-1,a,c,b)
        move(1,a,b,c) # 第二步、把第n个盘子由a经过’b‘移动到c:(1,a,b,c),---只有一个盘子了当然不用在经过b移动到c了,这么写只是为了使结构一致方便写递归函数
        move(n-1,b,a,c) # 第三步、把n-1个盘子由b经过a移动到c:(n-1,b,a,c)

move(7,'A','B','C')

移动次数

方法一

已知盘子的数量为n,计算把n个盘子从a经过b移动到c移动需要移动多少次。

如果按照上面的代码计算盘子的移动次数,时间会非常慢,因为上面的代码是模拟盘子的移动过程,盘子移动多少次,实际就递归多少次。

通过上面的代码可以发现一个规律:

  • 当n=1时,只移动一次
  • 当n>1时,
    • 先走个将n-1个盘子从a经由b移动到c的次数
    • 再走个将一个盘子直接从a移动到c的次数,也就是移动1次
    • 最后再走个将b上的n-1个盘子经由a移动到c的次数

从上面的规律可以看出,如果n=1,只移动1次,否则移动 2*move(n-1)+1次。于是就得到了求求移动次数的递归代码;

递归求盘子的移动次数


"""
有n个盘子,他需要从a借助于b移动到c,移动的次数是move(n):
    当n=1时,只需要移动1次
    当n=2时,
        先走个将n-1个盘子从a借助于c移动到b的次数,即:move(n-1)
        再将a上的最底下的那个盘子直接移动到c,即1次
        再走个将b上的n-1个盘子借助a移动到c的次数,即:move(n-1)

        也就是说当n>1时,走的次数是2*move(n-1)+1

"""
# 移动n个盘子需要的次数
n = 64
def move (n):
    if n == 1:
        return 1
    return 2*move(n-1)+1
print(move(n))
    

方法二

另外一种求n个盘子移动次数的方法是结论法:

盘子数目移动次数
1 2 1 − 1 = 2 0 = 1 2^1-1=2^0=1 211=20=1
2 2 2 − 1 = 2 0 + 2 1 = 3 2^2-1=2^0+2^1=3 221=20+21=3
3 2 3 − 1 = 2 0 + 2 1 + 2 2 = 7 2^3-1=2^0+2^1+2^2=7 231=20+21+22=7
n 2 n − 1 = 2 0 + 2 1 + 2 2 + . . . + 2 n − 1 2^n-1=2^0+2^1+2^2+...+2^{n-1} 2n1=20+21+22+...+2n1
所以,移动n的盘子需要的次数为:

python

import math
n = 64
print(int(math.pow(2,n)-1))
print(pow(2,n)-1) 

java

package demo.test1;

import java.math.BigInteger;
public class Main {
	public static void main(String[] args) {
		BigInteger bit = new BigInteger("2");//定义一个大整数类型的2
		bit = bit.pow(64);//2的64次方,并重新赋值给bit
		bit = bit.subtract(new BigInteger("1"));//大整数的减法,并重新赋值给bit
		System.out.println(bit);
	}
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

东篱把酒黄昏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值