【Python/C++ 递归】汉诺塔

汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘

在这里插入图片描述
1.游戏规则
条件: 有A、B、C三根柱子,A柱子按照上小下大放置圆盘。
规则: 每次只能移动1个圆盘,圆盘可在A、B、C三根柱子间任意移动,并且始终保持小盘在大盘上。
目标: 圆盘全部从A柱移动到C柱上,并且圆盘顺序不变,依旧是上小下大。
2.汉诺塔1-3层详解
汉诺塔是一道非常经典的递归问题,对于递归问题的求解,最重要的是找到递归公式,下面我们先通过观察1-3层汉诺塔移动方法,看看能不能找到一些规律。
🍑(1)一层汉诺塔
在这里插入图片描述
一层汉诺塔移动方法是:
移动第1个圆盘: A -> C

🍑(2)二层汉诺塔
在这里插入图片描述
二层汉诺塔移动方法:
移动第1个圆盘: A -> B
移动第2个圆盘: A -> C
移动第1个圆盘: B -> C

🍑(3)三层汉诺塔
在这里插入图片描述
三层汉诺塔移动方法:

移动第1个圆盘: A -> C
移动第2个圆盘: A -> B
移动第1个圆盘: C -> B
移动第3个圆盘: A -> C
移动第1个圆盘: B -> A
移动第2个圆盘: B -> C
移动第1个圆盘: A -> C

动图:

在这里插入图片描述
3.汉诺塔求解思路
观察过上面1-3层的汉诺塔的移动,你有没有找到一些规律呢?经过简单的归纳总结,我们大体可以得到这样的规律:

当汉诺塔层数n为1时:

将A柱上的1个圆盘直接挪到C柱上
当汉诺塔层数n为2时:

步骤1:先将A柱上第1个圆盘移动到B柱上
步骤2:再将A柱上剩下的1个圆盘直接移动到C柱上
步骤3:最后将B柱上的圆盘移动到C柱上

当汉诺塔层数n为3时:

步骤1:先将A柱上前2个圆盘移动到B柱上
步骤2:再将A柱上剩下的1个圆盘直接移动到C柱上
步骤3:最后将B柱上的圆盘移动到C柱上

那么当n=4的时候呢?

我们按照上述过程,可以想到这样的思路:

步骤1:先将前4-1个圆盘,从A柱借助C柱挪到B柱
步骤2:再将A柱上剩下的1个圆盘,从A柱直接挪到C柱
步骤3:最后将B柱上的4-1个圆盘,从B柱借助A柱挪到C柱

通过对上述过程的归纳,当为n层汉诺塔的时候,我们将其分为三步:

步骤1:先将前n-1个圆盘,从A柱借助C柱挪到B柱
步骤2:再将A柱上剩下的1个圆盘,从A柱直接挪到C柱
步骤3:最后将B柱上的n-1个圆盘,从B柱借助A柱挪到C柱

python 递归方式解汉洛塔问题:

def hanoi(n, a, b, c):
    if n == 1:
        print(f"Move disk 1 from {a} to {c}")
    else:
        hanoi(n-1, a, c, b)
        print(f"Move disk {n} from {a} to {c}")
        hanoi(n-1, b, a, c)

# 测试代码
n = 3
hanoi(n, 'A', 'B', 'C')

练习题:
【空汽水瓶】

题目描述

有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?

输入:

输入文件最多包含10组测试数据,每个数据占一行,仅包含一个正整数n(1<=n<=100),表示小张手上的空汽水瓶数。n=0表示输入结束,你的程序不应当处理这一行。

输出:

对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。

样例输入:
3
10
81
0

样例输出:
1
5
40

C++ 代码

#include<stdio.h>
int fun(int num){
    int nn,m,n,all=0;//nn表示换了之后有水的瓶子数
    //m表示换了之后空的瓶子数,all共可以喝到的水。 
    nn=num/3;
    m=num%3;
    n=nn+m;
    all=all+nn;
     
    if(n>=3){
    all=nn+fun(n); 
    }else if(n==2){
    all++;
    }
    return all; 
}
int main(){
    int num,a;
    int i=10;
    while(i){
    scanf("%d",&num);
    if(1<=num&&num<=100){
    a=fun(num);
    printf("%d\n",a);
    }
    if(num==0)break;
    i--;
    }
    return 0;
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值