初识汉诺塔问题

汉诺塔

汉诺塔(Tower of Hanoi)源于印度传说中,大梵天创造世界时造了三根金钢石柱子,其中一根柱子自底向上叠着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。

——引自维基百科

若给汉诺塔传说中三根柱子分别用英文字母a,b,c命名,其中只有a柱子摆放n片圆盘(1<=n<=100000), 若要把a柱子上的所有圆盘转移到c柱子上,问最少需要移动多少次圆盘。

移动圆盘的规则如下:

  1. 每次只能移动一片圆盘
  2. 直径大的圆盘必须摆放在直径小的圆盘之上

递归求解

汉诺塔问题通过简单的递归进行求解,代码比较简洁,通俗易懂。其实汉诺塔问题的移动次数是有规律可寻的,通过递归代码找出相应的规律,并通过数学方法得到结果效率才是最高的。

  • 当n=1时,a柱子只有一个圆盘,直接移至c柱
  • 当n>1时,根据规则1和2,将a柱子n-1个圆盘移动到b柱子,然后将a剩下的一个圆盘移动到c,接着再把b上暂时放着的n-1个圆盘移动到c

递归求解其实就是不断降低问题规模的过程,将b柱子的n-1个圆盘移至c何尝不重复上述两点的过程。递归求解的C代码如图3-1所示。

void Hanoi(int n, char a, char b, char c)
{
    if(n == 1)
    {
        Move(a, c);
    }
    else
    {
        Hanoi(n-1, a, c, b); /*将a柱子n-1个圆盘移动到b柱子*/
        Move(a, c);      /*将a剩下的一个圆盘移动到c*/
        Hanoi(n-1, b, a, c); /*再把b上暂时放着的n-1个圆盘移动到c*/
    }
}

void Move(char a, char b)
{
    printf("Move 1 disk: %c ---------> %c\n", a, b);
}

图3-1    汉诺塔递归求解代码

如图3-1的代码可以得出汉诺塔移动圆盘次数的递推关系:

  • Hanoi(n) = 1 , n =1 ;
  • Hanoi(n) = 2 * Hanoi(n-1) + 1, n>1;

令b(n) = Hanoi(n)+1,可以得出b(n)是一个以2为底,公比为2的等比数列。由此可得,

b(n) = 2n, n>0

Hanoi(n) = 2n - 1, n>0


增加约束条件的汉诺塔

Q: 若加上一个限制条件,圆盘只能在相邻柱子之间移动,又如何解决?假设a, b, c并排,b在中间,即a, c不相邻,把a上的一个圆盘移动到c上必须先移至b,然后再移动到c。

From TOJ 3270 Strange Hanoi Tower

同理使用递归求解,根据原有规则和新增约束条件,推导出移动圆盘的次数的规律。

  • 当n=1时,a柱子只有一个圆盘,先移到b,再移至c
  • 当n>1时,先将a柱的n-1个圆盘通过b柱移至c柱,再将a柱子剩下的一个圆盘移到b; 接着把c柱n-1个圆盘通过b柱移到a; 然后把b柱子目前唯一的圆盘移至c,最后把a柱子的n-1个圆盘通过b移至c

递归代码如图3-2所示。

void Hanoi(int n, char a, char b, char c)
{
    if(n==1)
    {              //a柱子只有一个圆盘,先移到b,再移至c
        Move(a, b);
        Move(b, c);
    }
    else
    {
        Hanoi(n-1, a, b, c); //先将a柱的n-1个圆盘通过b柱移至c柱
        Move(a, b);          //a柱子剩下的一个圆盘移到b
        Hanoi(n-1, c, b, a); //把c柱n-1个圆盘通过b柱移到a
        Move(b, c);          //把b柱子目前唯一的圆盘移至c
        Hanoi(n-1, a, b ,c); //把a柱子的n-1个圆盘通过b移至c
    }
}
void Move(char a, char b)
{
        printf("%c --> %c\n", a, b);
}

图3-2    增加约束条件的汉诺塔递归代码

由图3-2可得,移动圆盘次数与圆盘个数的递推关系,

  • 当n=1时,Hanoi(n) = 2;
  • 当n>1时,Hanoi(n) = 3 * Hanoi(n-1) + 2;

最后求得:

Hanoi(n) = 3n - 1, n>0

这道题目的结果可能会很大,输出的结果要 mod 1,000,000,007。

题目的输出提示让我很疑惑,结果很大和 mod 这个数有什么关系。百度一下,貌似与什么费马小定理有关。但是我还是看不懂,先留着再进行研究学习。

时间: 2024-10-20 13:02:20

初识汉诺塔问题的相关文章

C++学习:任意合法状态下汉诺塔的移动(原创)

汉诺塔问题: 问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘. 现在将问题变形为:初识时,n个金盘分散摆放在三根柱子上,并且所有金盘都处于合法状态,将这些分散的金盘全部移动到第三根柱子上,并打印每一次的移动步骤以及移动后三个柱子上金盘的状态. C++实现代码如下: 1 #ifnde

17.11.9 汉诺塔问题

描述 汉诺塔是约19世纪末,在欧州的商店中出售一种智力玩具.它的结构如下图所示:  在一个平板上立有三根铁针,分别记为A, B, C.开始时,铁针 A 上依次叠放着从大到小 n 个圆盘,游戏的目标就是将 A 上的 n 个圆盘全部转移到 C 上,要求每次只能移动某根铁针最上层一个圆盘,圆盘不得放在这三根铁针以外的任何地方,而且永远只能将小的圆盘叠放在大的圆盘之上. 例如,下面就是示例输出中(n = 3)移动方案的图示: 这是一个著名的问题,几乎所有的教材上都有这个问题.由于条件是一次只能移动一个盘

hdu 1207 汉诺塔II (DP+递推)

汉诺塔II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4529    Accepted Submission(s): 2231 Problem Description 经典的汉诺塔问题经常作为一个递归的经典例题存在.可能有人并不知道汉诺塔问题的典故.汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往

从汉诺塔问题来看“递归”本质

汉诺塔问题 大二上数据结构课,老师在讲解"栈与递归的实现"时,引入了汉诺塔的问题,使用递归来解决n个盘在(x,y,z)轴上移动. 例如下面的动图(图片出自于汉诺塔算法详解之C++): 三个盘的情况: 四个盘的情况: 如果是5个.6个.7个....,该如何移动呢? 于是,老师给了一段经典的递归代码: void hanoi(int n,char x,char y,char z){ if(n == 1) move(x,1,z); else{ hanoi(n-1,x,z,y); move(x,

bzoj1019: [SHOI2008]汉诺塔(dp)

1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 1739  Solved: 1062[Submit][Status][Discuss] Description 汉诺塔由三根柱子(分别用A B C表示)和n个大小互不相同的空心盘子组成.一开始n个盘子都摞在柱子A上,大的在下面,小的在上面,形成了一个塔状的锥形体. 对汉诺塔的一次合法的操作是指:从一根柱子的最上层拿一个盘子放到另一根柱子的最上层,同时要保证被移动的

汉诺塔(三)

汉诺塔(三) 描述 在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔.不论白天黑夜,总有一个僧侣在按照下面的法则移动这些金片:一次只移动一片,不管在哪根针上,小片必须在大片上面.僧侣们预言,当所有的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔.庙宇和众生也都将同归于尽. 现在我们把三根针编号为1,2,3. 所

python 实现汉诺塔问题

代码如下: def hano(n,x,y,z): if n==1: print(x,"->",z) else: #将n-1个盘子从x->y hano(n-1,x,z,y) #将剩余的最后一个盘子从x->z print(x,"->",z) #将剩余的n-1个盘子从y->z hano(n-1,y,x,z) n = int(input("请输入汉诺塔的层数:")) hano(n,"A","B&

NYOJ 93 汉诺塔(三) 【栈的简单应用】

汉诺塔(三) 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描写叙述 在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针.印度教的主神梵天在创造世界的时候.在当中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔. 不论白天黑夜,总有一个僧侣在依照以下的法则移动这些金片:一次仅仅移动一片.无论在哪根针上.小片必须在大片上面.僧侣们预言.当全部的金片都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中

汉诺塔的递归算法与解析

从左到右 A  B  C 柱 大盘子在下, 小盘子在上, 借助B柱将所有盘子从A柱移动到C柱, 期间只有一个原则: 大盘子只能在小盘子的下面. 如果有3个盘子, 大中小号, 越小的越在上面, 从上面给盘子按顺序编号 1(小),2(中),3(大), 后面的原理解析引用这里的编号. 小时候玩过这个游戏, 基本上玩到第7个,第8个就很没有耐心玩了,并且操作的动作都几乎相同觉得无聊.  后来学习编程, 认识到递归, 用递归解决汉诺塔的算法也是我除了简单的排序算法后学习到的第一种算法. 至于递归,简单来说