1. 程式人生 > >漢諾塔及其變形

漢諾塔及其變形

問題 using 記錄 表示 turn log 基礎上 pac int

漢諾塔

一、經典漢諾塔

有三根相鄰的柱子,標號為A,B,C,A柱子上從下到上按金字塔狀疊放著n個不同大小的圓盤,要把所有盤子一個一個移動到柱子B上,並且每次移動同一根柱子上都不能出現大盤子在小盤子上方,請問至少需要多少次移動,設移動次數為F(n)

設F[n]表示將n個盤從按規則從X柱移到Z柱至少需要移動的次數。

當n=1時,F[n]=1;

當n>1時,將移動盤之的過程分為三步:

1)將A柱上的n-1個盤依靠Z柱移到Y柱上,這個需要F[n-1]步;

2)將A柱上剩下的一個盤(最大的盤)移到C柱上,這個需要1步;

3)將B柱上的n-1個盤依靠A柱移到C柱上,這個需要F[n-1]步;

所以移完n個至少需要的步數F[n]=F[n-1]+1+F[n-1]=2*F[n-1]+1; 而F[1]=1;由以上兩個等式可以推出求F[n]的一般式,即F[n]=2^n-1;

二、漢諾塔II

轉自http://www.cnblogs.com/jackge/p/3218066.html

問題描述:在經典漢諾塔的基礎上加一個條件,即,如果再加一根柱子(即現在有四根柱子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]的最小值。

剛開始推了個dp[i]=2*dp[i-2]+3

結果沒想到只是一種情況,不是最優解,>_<,可憐的自己,好菜啊

#include <stdio.h>
#include <algorithm>
#include <memory.h>
#include <math.h>
using namespace std;

const int maxn=65;
double F[maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    for(int i=0;i<maxn;i++)F[i]=0x3f3f3f3f
; F[1]=1; F[2]=3; for(int x=3;x<=maxn;x++){ for(int i=1;i<x;i++){ F[x]=min(F[x],2*F[i]+pow(2,x-i)-1); } } int n; while(scanf("%d",&n)!=EOF){ printf("%d\n",(int)F[n]); } return 0; }

漢諾塔及其變形