每日算法练习——递归(Hanoi汉诺塔问题)

 知识补充:

由来

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

不管这个传说的可信度有多大,如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。n=64时,

假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下:

18446744073709551615秒

这表明移完这些金片需要5845.54亿年以上,而地球存在至今不过45亿年,太阳系的预期寿命据说也就是数百亿年。真的过了5845.54亿年,不说太阳系和银河系,至少地球上的一切生命,连同梵塔、庙宇等,都早已经灰飞烟灭。

摘自百度百科:https://baike.baidu.com/item/%E6%B1%89%E8%AF%BA%E5%A1%94/3468295?fr=aladdin

只能说很库!!!

没图说个**呀:

 

《每日算法练习——递归(Hanoi汉诺塔问题)》

上图为 3 阶 Hanoi 塔运行示意图

 

算法问题:

假设有三个命名为 A B C 的塔座 ,在塔座A上插有n个直径大小不相同,由小到大编号为1 ,2 ,3 ,··· ,n的圆盘,要求将A座上的圆盘移至塔座C

并按同样的顺序叠排

圆盘移动必须遵守下列规则:

1:每次只能移动一个圆盘 2:圆盘可以插在任意一个塔座上 3:任何时刻都不能将一个较大的圆盘放在一个较小的圆盘上

 

该问题的复杂性:

若有n个盘子,则移动完所需之次数为2^n – 1,

所以当盘数为64时,则所需次数为:

2^64 – 1 = 18446744073709551615

为5.05390248594782e+16年,也就是约5000世纪,如果对这数字没什么概念,就假设每秒钟搬一个盘子好了,也要约5850亿年左右。

 

以三阶Hanoi塔为例,我们所需要的7个步骤是:

1——>C

2——>B

1——>B

3——>C

1——>A

2——>C

1——>C

 

则对于n阶Hanoi塔:

n = 1时只需将编号为1的圆盘从A座移至C座

n > 1时,我们分三个阶段:

1:将A塔座上的n-1个圆盘按照规定移至到B塔座

2:将编号为n的圆盘由A座移至C座

3:利用A塔座,将B塔座上的n-1个圆盘按规定移至到C塔座

 

如何将n-1个圆盘由一个塔座移至到另一个塔座是一个和原问题有相同特征属性的问题,只是问题的规模小些,我们可以用同样的方法求解,这就是递归思想:

使用同样的方法解决和原问题有相同特征属性的子问题,层层递进直至到达最简情况(本题即为n=1)进行递回,以解决问题。

 

实现代码C语言

#include <stdio.h>
#include <stdlib.h>

// 递归求解hanoi问题
// 把n个盘子从x借助y移动到z
void Hanoi(int n,char x,char y,char z)
{
    if(n==1)
        printf("%c-->%c\n",x ,z );
    else
    {
        Hanoi(n-1,x,z,y);   // 把n-1个盘子从x借助z移动到y
        printf("%c-->%c\n",x ,z );    // 把第n-1个盘子从x移动到z
        // 接下来解决x上n-1个盘子的hanoi子问题
        Hanoi(n-1,y, x ,z );    // 把n-1个盘子从y上借助x移动到z上
    }

}

int main()
{
    char x='A',y='B',z='C'; //xyz表示三个盘子
    int n;
    while(1)
    {
        printf("请输入盘子的数量:\n");
        scanf("%d",&n);
        printf("移动步骤如下:\n");
        Hanoi(n,x,y,z);
        printf("DOWN!\n");
    }

    return 0;
}

 

点赞