汉诺塔


汉诺塔源于印度一个古老传说的益智类游戏。传说上帝创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。以上是来自百度百科的说法,有兴趣的可以到网上搜一下。之所以把汉诺塔作为第一个游戏来讲,并非因为它本身是计算机编程中描述递归算法的经典例子,而是因为它是我第一个尝试用计算机编程解决自己感兴趣的问题。记得那是2001年的秋天,比以往来得更热一些,在很多同学都躲到学校计算机阅览室纳凉的时候,我选择在浴室冲澡来对抗酷暑。闲来无事,开始摆弄室友的汉诺塔,突然想到用计算机去计算一下移动步骤呢?

游戏规则

    有三根并列的柱子,分别为A,B,C,初始的时候,A柱子上,从上到下摆放着N个盘子,盘子按小到大先后排列,小的盘子在上,大的盘子在下。玩家要做的就是把A柱子上的一堆盘子移动到另外一根柱子上,要求保持大小顺序不变,一次只能移动一个盘子,并且不能出现大的盘子在小的盘子上面的情况。

分析

为了使问题简单,我们先假设N=1,2,3的情况,先分析一下

当N =1时,只需要一步

当N=2时,先将小的盘子拿到B,然后将大的盘子拿到C,再将小盘子移动到C,总共三步

当N =3时,情况稍微复杂,我们不妨把前面两个小的盘子当做一个整体,把他们移动到柱子B上刚好需要N=2的步数,把大的盘子移动到C,最后把小的两个盘子移动到C上,总共需要7步。同理可以推得N=4,5,6….的搬运过程。

 

通过上述简单的分析,我们可以知道,要计算N个盘子的移动情况,只需要计算N-1的情况即可,而N-1又可以从N-2得到,直到最后问题规模等于1为止。对于N个盘的汉诺塔来说,可以将移动过程分解为,先从A柱移动N-1个盘到B,再从A柱把第N个盘移动到C,最后把B柱上的N-1个盘子移动到C,移动完成。

/*

move n disk from a to c

*/


 


int hanoi(char n,char a,char b,char c)

{    
    int count;     
    if(n==1)     
    {     
        printf("%c-->%c  \n", a, c);     
        return 1;     
    }     
    else{     
        count = hanoi(n-1,a,c,b);     
        printf("%c-->%c  \n", a, c);     
        count += hanoi(n-1,b,a,c);     
        count++;     
    }     
    return count;     
}

void main()

{    
    char n;     
    int count;     
    clock_t start, finish;     
    double duration;     
    printf("number of N:\n");     
    scanf("%d",&n);     
    printf("show details....\n");     
    start = clock();     
    count = hanoi(n,'A','B','C');     
    finish = clock();     
    duration = (double)(finish - start) / CLOCKS_PER_SEC;     
    printf( "%f seconds\n", duration );     
    printf("the steps needed to transfer all  %d diskes: is %d\n",n,count);     
}

hanoi函数用于计算移动的次数并且输出移动过程,clock()函数用于计算程序运行的时间。

下面用分别用N=3,8,15个例子看一下程序的运行时间

N =3


N=8


N=15

 

在我i3的机器上运行时间如上所示,基本为指数级增长,主要时间花费在printf输出上,但是当N越大的时候,比如20,运算时间已经比较长了。有兴趣的朋友可以试试。其实如果只是计算汉诺塔的移动次数,不需要这么麻烦,很容易可以证明n个盘的移动次数f(n)=2^n-1,可以直接通过计算给出对应的计算步骤,当然,对于n 比较大的时候,如64,int类型是无法存储这么大的空间的,可以使用double类型,其存储范围在1.79769e+308,2.22507e-308。要是再大,可以考虑通过数组存储,网上有类似算法,有兴趣的可以参考一下。

下节预告 24点

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值