1. 程式人生 > >漢諾塔系列問題: 漢諾塔II、漢諾塔III、漢諾塔IV、漢諾塔V、漢諾塔VI、漢諾塔VII

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

 漢諾塔II:(hdu1207)

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

規則小的必需放在大的上面,每次搬一個,求最小步數。這個問題簡單,DP:a[n]=a[n-1]+1+a[n-1],先把

上面的n-1個放在B上,把最大的放在目標C上,再把N-1個放回到C上即可。

</pre><p></p>現在是漢若塔II,改為四個塔,開始方程想簡單了,不是最優的。給出網上的一種最優解法如下:(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]的最小值。方法很容易理解,但是還有其他擺法(如第一步未必先要把所有X個放到一個非目標底座上),目前無法證<p>明其最優性,證明還需求路過大神指導。</p><p></p><pre name="code" class="cpp">#include<iostream>
#include<cmath>
using namespace std;
unsigned long long a[65];
 const unsigned long long one=1;
int main()
{
    a[1]=1;a[2]=3;
    for(int i=3;i<65;i++)
    {
       unsigned long long min=(one<<(i-1))-1+2*a[1];
        for(int j=2;j<i;j++)
        {
            if(2*a[j]+(one<<(i-j))-1<min)
             min=2*a[j]+(one<<(i-j))-1;
        }
        a[i]=min;
    }
    int n;
    while(cin>>n)
    {
        cout<<a[n]<<endl;
    }
    return 0;
}


漢若塔III  hdu2064

在經典漢若塔問題的條件改為,每次只能移動到附近塔上,求把A塔所有的移動C塔最小次數。

a[n]=a[n-1]+1+a[n-1]+1+a[n-1]:先把上面的N-1個移動到C(必然有這個狀態),在把最大的移到B,再把N-1移到到A,把最大的移到C,再把N-1個移到C,就上面的方程。分分鐘搞定~~~

#include<iostream>
#include<cmath>
using namespace std;
unsigned long long a[65];
int main()
{
    a[1]=2;
    for(int i=2;i<36;i++)
    {
        a[i]=3*a[i-1]+2;
    }
    int n;
    while(cin>>n)
    {
        cout<<a[n]<<endl;
    }
    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],

會發現bc[]方程和ab[n]一樣的。所以總方程ans[n]=2*ab[n-1]+2.

#include<iostream>
#include<cmath>
using namespace std;
unsigned long long ac[23];
unsigned long long bc[23];
unsigned long long ans[23];
int main()
{
    ac[1]=2;bc[1]=1;ans[1]=2;ans[2]=4;
    for(int i=2;i<22;i++)
    {
        ac[i]=3*ac[i-1]+2;
        bc[i]=bc[i-1]+1+ac[i-1];
    }
     for(int i=3;i<22;i++)
    {
        ans[i]=2*bc[i-1]+2;
    }
    int tt,n;
    cin>>tt;

    while(tt--)
    {
        cin>>n;
        cout<<ans[n]<<endl;
    }
    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又一次,思路清晰,分分鐘KO。

#include<iostream>
#include<cmath>
using namespace std;
unsigned long long dp[62][62];
int main()
{
    dp[1][1]=1;dp[2][1]=2;dp[2][2]=1;
    for(int i=3;i<61;i++)
    {
       for(int j=1;j<i;j++)
       {
           dp[i][j]=2*dp[i-1][j];
       }
       dp[i][i]=1;
    }
    int t;
    int n,m;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        cout<<dp[n][m]<<endl;
    }
    return 0;
}


漢若塔VI HDU1996
在經典漢若塔問題上,求一共有多少個狀態(包括所有可能移到到的狀態),一個排列組合問題,
答案:求和( C(k1,n)*C(k2,n-k1))其中n>=k1>=0,n-k1>=K2>=0,從中挑出K1個從小到大放在A塔,再從剩下的
挑出K2個放在B塔,剩餘的放在C塔即可。資料非大數。

其他巧妙方法:每個盤從小到大每個都有3種選擇,共3^n。

#include<iostream>
using namespace std;
unsigned long long a[32];
long long C(int m,int n)  //M>=N
{
    if(m==0||n==0)return 1;
       int i;
       long long c=1,s=1;
       if(n>m-n)
       {
                n=m-n;
       }
       for(i=m;i>=m-n+1;i--)
       {
           c=c*i;
       }
       for(i=n;i>1;i--)
       {
             s*=i;
        }

       c=c/s;
       return c;
}
int main()
{
    for(int i=1;i<30;i++)
    {
       for(int k1=0;k1<=i;k1++)
       {
          for(int k2=0;k2<=i-k1;k2++)
             {
                 a[i]+=C(i,k1)*C(i-k1,k2);
             }
       }
    }
    int t;
    int n,m;
    cin>>t;
    while(t--)
    {
        cin>>n;
        cout<<a[n]<<endl;
    }
    return 0;
}



漢諾塔VII hdu1997 在經典漢若塔問題上,給出任意一個狀態(移到過程中),判斷該狀態是否在正確的(最小移到情況)狀態
中。
思路:做到這題,漢若塔就很清晰了,有幾步、幾個狀態、狀態的正確性、每個盤子的移到情況,都瞭如指掌。說說該題思路:
n號塔必然是A->C,那麼N-1號塔, 若n在A,則n-1 在A或B,

見圖:


#include<iostream>
using namespace std;
char get[68];           //儲存I號盤子在哪個塔
bool over=0; bool tf=1;  //是否結束,true_or_false是否為假
void dfs(char fl,char fr, char cur,int now)  // dfs ,上面一層(now)左邊和右邊的塔,已經從哪個塔“下來的”(上面一層是哪個塔)
{
    if(over)return;
    if(now==1){over=1;return;}  //出口
    int temp;
    if(fl=='A'&&fr=='B'||fl=='B'&&fr=='A')temp='C';
    else if(fl=='A'&&fr=='C'||fl=='C'&&fr=='A')temp='B';
    else temp='A';
    now--;
    if(cur==fl)   //若上一層是左邊的塔
    {
        if(get[now]==fr){over=1;tf=0;return;}  //不可能是fr
        else
        {
            dfs(fl,temp,get[now],now);  
        }
    }
    else if(cur==fr)
    {
        if(get[now]==fl){over=1;tf=0;return;}
        else
        {
            dfs(temp,fr,get[now],now);
        }
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int n,m,p,q,tx;
        cin>>n;
        cin>>m;
        for(int i=0;i<m;i++)
        {
            cin>>tx;get[tx]='A';
        }
        cin>>p;
        for(int i=0;i<p;i++)
        {
            cin>>tx;get[tx]='B';
        }
        cin>>q;
        for(int i=0;i<q;i++)
        {
            cin>>tx;get[tx]='C';
        }
        tf=1;
        over=0;
        if(get[n]=='B')
        {
            cout<<"false"<<endl;continue;
        }
        dfs('A','C',get[n],n);
        if(tf==1)cout<<"true"<<endl;
        else cout<<"false"<<endl;
    }
    return 0;
}


相關推薦

系列HDU 2064,2077

漢諾塔Ⅲ 題目連結: 題目: 漢諾塔III                                                  時間限制:1000/1000 MS(Java /

系列問題 IIIIIIVVVIVII

 漢諾塔II:(hdu1207) /先說漢若塔I(經典漢若塔問題),有三塔,A塔從小到大從上至下放有N個盤子,現在要搬到目標C上, 規則小的必需放在大的上面,每次搬一個,求最小步數。這個問題簡單,DP:a[n]=a[n-1]+1+a[n-1],先把上面的n-1個放在B上,把

系列問題 IIIIIIVVVI

漢諾塔 漢諾塔II hdu1207: 先說漢若塔I(經典漢若塔問題),有三塔,A塔從小到大從上至下放有N個盤子,現在要搬到目標C上, 規則小的必需放在大的上面,每次搬一個,求最小步數。這個問題簡單,D

密爾頓維斯潘本來可以換一種處理方式

“90後”女大學生放棄北大保送復旦!她到底有多厲害?  東北網12月6日訊(記者 姜姍姍) 在東北農業大學有這樣一個自強不息的女大學生,她放棄北大直博被保送到復旦大學藥學院。她本科期間獲得國家獎學金、國家勵志獎學金、新東方自強獎學金、第一屆全國大學生生命聯賽國家二等獎……被評為黑龍江省“三好學生”。她就是生命

通天導遊各種程式語言的優缺點

【譯註】:聖經記載:在遠古的時候,人類都使用一種語言,全世界的人決定一起造一座通天的塔,就是巴別塔,後來被上帝知道了,上帝就讓人們使用不同的語言,這個塔就沒能造起來。 巴別塔不建自毀,與其說上帝的分化將人類的語言複雜化,不如說是人類自身心靈和諧不再的分崩離析。之所以

線上基於token認證的基礎知識詳解

一、    什麼是TokenToken原始的意思是“令牌”,是服務端生成的一個自定義字串,作為客戶端進行資料請求的一個標識。在區塊鏈興起後,Token被賦予“代幣”或“通證”的含義,意思是一種可流通的加密數字權益證明。二、    Token的起源早在計算機網路剛興起時,Tok

線上架構實踐基礎之一圖勝千言

設計圖,它不是簡單的供你欣賞,他其實是架構師,產品經理,開發工程師,測試工程師等各種角色之間進行溝通的語言,溝通的一個橋樑,讓整個團隊更能有效的協調工作。 設計圖不單單是架構師要掌握的,在一個產品的開發過程中,任何一個環節,任何一個角色都可以通過掌握不同的設計圖來完成溝通的

悖論一個跑得最快的人永遠追不上跑得最慢的人

  這是一個非常著名的悖論,而且我相信很多人都聽過。用現代的說法就是:“龜兔賽跑”。這個悖論是義大利哲學家芝諾(Zenon Eleates,約公元前490年-公元前436年)提出的4個關於運動的悖論之一,嘿嘿,一算離現在已經將近2500年了呢!這個悖論當時在學術圈引起了極大的關注,按照一般的思維我們還真難找出

物聯網平臺構架系列Amazon, Microsoft, IBM IoT 平臺導論 之三 連接

物聯網; iot; aws; 亞馬遜; greengrass;microsoft; azure;ibm; watson; bluemix 最近研究了一些物聯網平臺技術資料,以做選型參考。腦子裏積累大量信息,便想寫出來做一些普及。作為科普文章,力爭通俗易懂,不確保概念嚴謹性。我會給考據癖者提供相關英文

物聯網平臺構架系列Amazon, Microsoft, IBM IoT 平臺導論 之二 設備

物聯網; iot; aws; 亞馬遜; greengrass;microsoft; azure;ibm; watson; bluemix 最近研究了一些物聯網平臺技術資料,以做選型參考。腦子裏積累大量信息,便想寫出來做一些普及。作為科普文章,力爭通俗易懂,不確保概念嚴謹性。我會給考據癖者提供相關英文

HTML5 進階系列indexedDB 數據庫

連接數據庫 function request html5 客戶端 前言在 HTML5 的本地存儲中,有一種叫 indexedDB 的數據庫,該數據庫是一種存儲在客戶端本地的 NoSQL 數據庫,它可以存儲大量的數據。從上篇:HTML5 進階系列:web Storage ,我們知道

詳解C# 網絡編程系列實現類似QQ的即時通信程序

並且 會話 hat chat .sh odin unicode 情況 plist 引言: 前面專題中介紹了UDP、TCP和P2P編程,並且通過一些小的示例來讓大家更好的理解它們的工作原理以及怎樣.Net類庫去實現它們的。為了讓大家更好的理解我們平常中常見的軟件QQ的工作原理

問題解決系列 後臺服務流量控制- 控制訪問別的服務的速度

發送 template 個人 exce 保護 rms 這一 ole 每分鐘 互聯網的後臺提倡大系統小做,微服務化。所以後臺服務之間相互依賴,我依賴別人的,別人也依賴我的,這很正常。但是後臺服務講穩定性。只有一切可控,才能談穩定性。為了不沖垮下遊的服務,我們有兩種做法:一種是

深入Java集合學習系列HashSet的實現原理

是否 abstract arc html 源代碼 cat param body static 0.參考文獻 深入Java集合學習系列:HashSet的實現原理 1.HashSet概述:   HashSet實現Set接口,由哈希表(實際上是一個HashMap實例)支持。它

Linux基礎系列常用命令(2)

用戶和組 查看 -- tdi 作業二 其他 配置文件 解鎖 gid 1 作業一: 2 1) 新建用戶natasha,uid為1000,gid為555,備註信息為“master” 3 groupadd -g 555 natasha 4 useradd -u

AngularJS 1.x系列AngularJS簡介及第一個應用(2)

ref http 源碼 1.2 lar div targe all clas 1. 安裝AngularJS 1.1 AngularJS官網   Github源碼:https://github.com/angular/angular.js   官網:https://an

Linux基礎系列常用命令(5)_nfs服務與nginx服務

ash .com access emctl 磁盤 keepalive roo inux iptable 介紹:   NFS 是Network File System的縮寫,即網絡文件系統。一種使用於分散式文件系統的協定,由Sun公司開發,於1984年向外公布。功能是通過

簡單算法系列快速算法/冒泡算法兩則

mil 小例子 turn int 設計 pan 問題 體會 理解 工作較忙,沒辦法抽出時間專心攻克《Go語言編程》,隨著了解的更多,越發體會出這本書中小例子的精巧。 掌握這些小例子,就可以完成Go基礎的全面掌握 最近抽出時間專心敲這些例子。但是發現一些問題,在設計上,許大大

架構的坑系列重構過程中的過度設計

一件事 都是 。。 上層 實現 軟件 太行 事件 -m 架構的坑系列:重構過程中的過度設計 軟件架構 2016-06-03 08:47:02 發布 您的評價: 5.0 收藏 2收藏 這個系列是 坑 系列,