漢諾塔系列問題: 漢諾塔II、漢諾塔III、漢諾塔IV、漢諾塔V、漢諾塔VI

漢諾塔php

漢諾塔II hdu1207:算法

先說漢若塔I(經典漢若塔問題),有三塔。A塔從小到大從上至下放有N個盤子。現在要搬到目標C上。post

規則小的必需放在大的上面,每次搬一個。求最小步數。

這個問題簡單,DP:a[n]=a[n-1]+1+a[n-1],先把
spa

上面的n-1個放在B上,把最大的放在目標C上,再把N-1個放回到C上就能夠。code

網上的一種最優解法例如如下:(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)步結束後任務完畢。blog

故完畢任務所需要的總的步數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]的最小值。
ip

#include"stdio.h"
#include"string.h"
#include"math.h"
#define N 66
#define Inf 0x7fffffff
int main()
{
    __int64 i,j,min,f[N]={0,1,3};;
    for(i=3;i<N;i++)
    {
        min=Inf;
        for(j=1;j<i;j++)
        {
            if(min>2*f[j]+pow(2.0,1.0*i-j)-1)  //pow的返回值會超出64位。不能強制轉換爲整數
                min=2*f[j]+pow(2.0,1.0*i-j)-1; //注意兩個參數應該都爲double型。!

} f[i]=min; } while(scanf("%I64d",&i)!=-1) { printf("%I64d\n",f[i]); } return 0; } get


漢若塔III  hdu2064:

先把上面的N-1個移動到C(一定有這個狀態)。在把最大的移到B,再把N-1移到到A。把最大的移到C,再把N-1個移到C。
string

遞推公式:f[n]=f[n-1]+1+f[n-1]+1+f[n-1]; 即f[n]=3*f[n-1]+2;io

#include"stdio.h"
#include"string.h"
#include"math.h"
#define N 36
int main()
{
    __int64 n,i,f[N]={2};
    for(i=1;i<N;i++)
    {
        f[i]=3*f[i-1]+2;
    }
    while(scanf("%I64d",&n)!=-1)
    {
        printf("%I64d\n",f[n-1]);
    }
    return 0;
}


漢若塔IV HDU 2077

在漢若塔3的基礎上。改條件:贊成最大的盤子放到最上面(僅僅贊成最大的放在最上面)固然最後需要的結果仍是盤子從小到大排在最右邊。

A,B,C三個塔。方程:ans[n]=ab[n-1]+1+1+bc[n-1]. (ab表示a到b)

DP思路:先把n-1個搬到b,再用倆步般最大的到C。再把n-1個從B到C。這裏又要求出ac[n]和bc[n]:求其遞推方程:bc[n]=bc[n-1]+1+ac[n-1],(1式)

會發現bc[n]方程和ab[n]同樣的。

因此總方程ans[n]=2*bc[n-1]+2. (2式)

#include"stdio.h"
#include"string.h"
#include"math.h"
#define N 21
int main()
{
    int i,T;
    __int64 ac[N],bc[N],ans[N];
    ac[1]=2;
    bc[1]=1;
    for(i=2;i<N;i++)
    {
        ac[i]=3*ac[i-1]+2;
        bc[i]=bc[i-1]+ac[i-1]+1;
        ans[i]=2*bc[i-1]+2;
    }
    ans[1]=2;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&i);
        printf("%I64d\n",ans[i]);
    }
    return 0;
}

漢若塔V HDU1995
在經典漢若塔問題上附加問題:求出N個盤子時,第K號盤子的移動次數。
思路。一想就是二維DP,DP[n][i]=dp[n-1][i]*2(1=<i<n),dp[n][n]=1;
最大盤僅僅移動一次,上面盤子先移到B塔,一次,最後由B到目標C從新.。

#include"stdio.h"
#include"string.h"
#include"math.h"
#define N 61
int main()
{
    __int64 i,j,f[N][N];
    f[1][1]=f[2][2]=1;
    f[2][1]=2;
    for(i=3;i<N;i++)
    {
        f[i][i]=1;
        for(j=1;j<i;j++)
        {
            f[i][j]=2*f[i-1][j];
        }
    }
    int T,n,m;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        printf("%I64d\n",f[n][m]);
    }
    return 0;
}

漢若塔VI HDU1996
 每個盤從小到大每個都有3種選擇,共3^n。


#include"stdio.h"
#include"string.h"
#include"math.h"
#define N 61
int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        printf("%.0f\n",pow(3.0,n*1.0));
    }
    return 0;
}
相關文章
相關標籤/搜索