1. 程式人生 > >hdu1207漢諾塔II四柱

hdu1207漢諾塔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

問題描述:在經典漢諾塔的基礎上加一個條件,即,如果再加一根柱子(即現在有四根柱子a,b,c,d),計算將n個盤從第一根柱子(a)全部移到最後一根柱子(d)上所需的最少步數,當然,也不能夠出現大的盤子放在小的盤子上面。注:1<=n<=64;
分析:設F[n]為所求的最小步數,顯然,當n=1時,F[n]=1;當n=2時,F[n]=3;如同經典漢諾塔一樣,我們將移完盤子的任務分為三步:
(1)將x(1<=x<=n)個盤從a柱依靠b,d柱移到c柱,這個過程需要的步數為F[x];
(2)將a柱上剩下的n-x個盤依靠b柱移到d柱(注:此時不能夠依靠c柱,因為c柱上的所有盤都比a柱上的盤小)
些時移動方式相當於是一個經典漢諾塔,即這個過程需要的步數為2^(n-x)-1(證明見再議漢諾塔一);
(3)將c柱上的x個盤依靠a,b柱移到d柱上,這個過程需要的步數為F[x];
第(3)步結束後任務完成。
故完成任務所需要的總的步數F[n]=F[x]+2^(n-x)-1+F[x]=2*F[x]+2^(n-x)-1;但這還沒有達到要求,題目中要求的是求最少的步數,易知上式,隨著x的不同取值,對於同一個n,也會得出不同的F[n]。即實際該問題的答案應該min{2*F[x]+2^(n-x)-1},其中1<=x<=n;可以用迴圈的方式,遍歷x的各個取值,並用一個標記變數min記錄x的各個取值中F[n]的最小值。
數值不是很大,int完全可以搞定,程式碼如下:

#include <iostream>
#include <cmath>
using namespace std;
const int INF=9999999;

int f[65];
void init()
{
    f[1]=1;f[2]=3;
    for(int i=3;i<65;i++)
    {
        int min_x=INF;
        for(int x=1;x<i;x++)
        {
            if(2*f[x]+pow(2.0,i-x)-1<min_x)
            min_x=2*f[x]+pow(2.0,i-x)-1;
        }
//        寫成下面這樣就錯了,估計是tmp溢位了
//        for(int x=1;x<i;x++)
//        {
//            int tmp=2*f[x]+pow(2.0,i-x)-1;
//            if(tmp<min_x)
//            min_x=tmp;
//        }
        f[i]=min_x;
    }
}
int main()
{int n;
 init();
 while(cin>>n)
 {
     cout<<f[n]<<endl;
 }

    return 0;
}