hdu1027

汉诺塔II

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3730    Accepted Submission(s): 1855


Problem Description
经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。Gardon就收到了一个汉诺塔玩具作为生日礼物。
  Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
 

 

Input
包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)。
 

 

Output
对于每组数据,输出一个数,到达目标需要的最少的移动数。
 

 

Sample Input
1 3 12
 

 

Sample Output
1 5 81
分析:
注:1<=n<=64;
分析:设hanoi[n]为所求的最小步数,显然,当n=1时,hanoi[n]=1;当n=2时,hanoi[n]=3;如同经典汉诺塔一样,我们将移完盘子的任务分为三步:
(1)将j(1<=j<=n)个盘从a柱依靠b,d柱移到c柱,这个过程需要的步数为hanoi[j];
(2)将a柱上剩下的n-j个盘依靠b柱移到d柱(注:此时不能够依靠c柱,因为c柱上的所有盘都比a柱上的盘小)这个时候移动方式相当于是一个经典汉诺塔,即这个过程需要的步数为2^(n-j)-1;
(3)将c柱上的 j 个盘依靠a,b柱移到d柱上,这个过程需要的步数为hanoi[j];
第(3)步结束后任务完成。
故完成任务所需要的总的步数hanoi[n]=hanoi[j]+2^(n-j)-1+hanoi[j]=2*hanoi[j]+2^(n-j)-1;但这还没有达到要求,题目中要求的是求最少的步数,易知上式,随着j的不同取值,对于同一个n,也会得出不同的hanoi[n]。即实际该问题的答案应该min{2*hanoi[j]+2^(n-j)-1},其中1<=j<=n;,我们可以用循环的方式,遍历j的各个取值,并用一个标记变量min记录j的各个取值中hanoi[n]的最小值。
#include<stdio.h>
#include<math.h>
int main()
{
    int n,min,hanoi[65],j,i;
    hanoi[1]=1;
    hanoi[2]=3;
    for(i=3;i<65;i++)
    {
        min=99999999;
        for (j=1;j<i;j++)
            if (2*hanoi[j]+pow(2.0,i-j)-1< min)
               min = 2*hanoi[j]+(int)pow(2.0,i-j)-1;
        hanoi[i]=min;
    }
    while(~scanf("%d",&n))
          printf("%d\n",hanoi[n]);
    return 0;
}
posted @ 2013-08-19 16:21  我家小破孩儿  阅读(153)  评论(0编辑  收藏  举报