汉诺塔及变式(含详细代码)

本文深入探讨了汉诺塔游戏的两种玩法,包括普通汉诺塔及其变式,详细分析了移动步骤的数学模型,提供了具体的算法实现代码,适合对算法和游戏策略感兴趣的读者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

汉诺塔介绍

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。

普通汉诺塔

我们先来对汉诺塔的步数进行一下递推

对于n个盘子,我们可以把它分成n−1个盘子和最后一个大盘子

设F(n)为移动所需步数,那么对于n个盘子来说所做的事情就是将n−1个盘子借助C柱移动到B柱上,这一过程移动的步数为F(n−1) (F(n)其实就是将n个盘子借助B柱移动到C柱上,注意:借助柱和目标柱互换名称是不改变移动步数的)

下一步我们将大盘子移动到C柱上,此时需要一步,最后,我们再将n−1盘子借助A柱移动到C柱上,此时需要的步数仍为F(n−1)

综合以上分析得到:

F n = 2 F n − 1 + 1 ( F 1 = 1 , n ≥ 2 ) \begin{aligned}F_{n}=2F_{n-1}+1\\ \left( F_{1}=1,n\geq 2\right) \end{aligned} Fn=2Fn1+1(F1=1,n2)
对两边同时加上1可以凑成一个等比数列,然后就可以求出其通项公式:
F n = 2 n − 1 ( n = 1 , 2 , … ) \begin{aligned}F_{n}=2^{n}-1\\ \left( n=1,2,\ldots \right) \end{aligned} Fn=2n1(n=1,2,)
代码:

#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
int ans = 0, n;
long long ans2 = 0;
void hmove(char a, char b, char c, int n){
    if(n == 0){return ;}
    hmove(a, c, b, n - 1);        //前n - 1块从a移动到b上
    printf("%c -> %c\n", a, c);   //我自己移动一块从a -> c
    ans++;                        //我移动了几次?
    hmove(b, a, c, n - 1);        //最后把 n - 1块从b移动到c上
}
int main(){
    scanf("%d", &n); 
    printf("普通汉诺塔:\n");
    hmove('a', 'b', 'c', n);                
    printf("%d\n", ans);
}

汉诺塔变式

限定条件:

限定圆盘只能够移动到相邻的柱子,即a柱子上的圆盘只能够移动到b,b柱子上的圆盘只能够移动到a或者c,c同理。

思路:

同样的,对于n个盘子,我们可以把它分成n−1个盘子和最后一个大盘子

同样设F(n)为移动所需步数, 将n−1盘子借助B柱移动到C柱上,这一过程移动的步数极为F(n−1),将大盘子由A柱移动到B柱上,此时需要一步,将n−1个盘子借助B柱移动到A柱上,这一过程移动的步数同样为F(n−1) 将大盘子由B柱移动到C柱上,此时需要一步,将n−1个盘子借助B柱子移动到C柱上,此时需要的步数仍为F(n−1)

综合以上分析,得到:
F n = 3 F n − 1 + 2 ( F 1 = 2 , n ≥ 2 ) \begin{aligned}F_{n}=3F_{n-1}+2\\ \left( F_{1}=2,n\geq 2\right) \end{aligned} Fn=3Fn1+2(F1=2,n2)
同样,对两边同时加上1可以凑成一个等比数列,最后求出其通项公式即为
F n = 3 n − 1 ( n = 1 , 2 , … ) \begin{aligned}F_{n}=3^{n}-1\\ \left( n=1,2,\ldots \right) \end{aligned} Fn=3n1(n=1,2,)
代码:

void hmove2(char a, char b, char c, int n){
    if(n == 0){
        return ;
    }
    hmove2(a, b, c, n - 1);                    //把前n - 1块通过b移动到c上
    ans2++;                                    //把最后一块移动到b上
    printf("%c -> %c\n", a, b);
    hmove2(c, b , a, n - 1);                  //把n - 1 块通过b移动到a上
    ans2++;                                   //把最后一块移动到c上
    printf("%c -> %c\n", b, c);
    hmove2(a, b, c, n - 1);                   //把剩下的n - 1块通过b移动到c上
}

本文参考资料

大吉大利,今晚吃鸡题目题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值