汉诺塔II

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


这道题需要自己发一些时间去推一下,个数是123时可以轻易算出,

其他情况就是可以根据移动上面j个,然后将下面的n-j个移动最后

一根柱子(那么就是2^(n-j),因为相当于三根柱子的移动),最后

移回来,即最优答案为

ans[i] = min { ans[j]*2+2^( n-j )-1 } 1 <= j < i

感觉应该是可以优化第二层循环的(自己再好好考虑)。

#include <stdio.h>
#define INF 0x7fffffff
#define ULL unsigned long long
const int maxn = 68, mod = 10000;
ULL ans[maxn], bit[maxn];   //因为可能为2^64,所以用无符号
int main ( )
{
    ans[1] = 1, ans[2] = 3, ans[3] = 5;
    bit[0] = 1;
    for ( int i = 1; i < maxn; i ++ )
        bit[i] = bit[i-1]*2;    //保存2^i
    for ( int i = 4; i < maxn; i ++ )
    {
        ULL mn = INF;
        int pos;
        for ( int j = 1; j < i; j ++ )
        //将上面j个移动一根柱子上,并且需要移动最后一根,所以需要2*ans[j],剩下的就相当于三根柱子的移动了
            if ( mn > 2*ans[j]+bit[i-j]-1 )
            {
                mn = 2*ans[j]+bit[i-j]-1;
                pos = j;
            }
        //printf ( "%d\n", pos );
        ans[i] = mn;
    }
    int n;
    while ( ~ scanf ( "%d", &n ) )
        printf ( "%u\n", ans[n] );
    return 0;
}


你可能感兴趣的:(汉诺塔II)