日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼

發布時間:2025/3/21 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我想很多人第一次學習遞歸的時候,老師或者書本上可能會舉漢諾塔的例子。

但是今天,我們討論的重點不是簡單的漢諾塔算法,而是三柱漢諾塔的延伸。先來看看經典的三柱漢諾塔。

?

一、三柱漢諾塔(Hanoi_Three):

我想大家對于三柱漢諾塔的理解以及算法的實現應該是很熟練了。

我在這里簡單的過一遍三柱漢諾塔的算法思想:

有A、B、C三根柱子,A柱上有n個盤子,現在需要將A上所有的盤子轉移到C上,請給出搬運次數最少的步驟。

?

算法思想:

1、將A上n-1個盤子以C為緩存,全部轉移到 B 柱上。

2、將A上留下的第n個盤子,直接轉移到 C? 柱上。

3、將B上的n-1個盤子,以A為緩存,全部轉移到 C 柱上。

?

很容易得到算法的遞歸方程為:T(n)=2*T(n-1)+1,不難算出步數是T(n)=2^n-1

?

具體的代碼如下:

[cpp]?view plaincopy
  • void?Move(?char?x,?char?y?)??
  • {??
  • ????printf("%c?-->?%c\n",?x,?y);?//打印路徑,x-->y??
  • }??
  • ??
  • void?Hanoi_Three(?int?n,?char?a,?char?b,?char?c?)??
  • {??
  • ????if(?n?<=?0?)??
  • ????????return?;??????
  • ??????
  • ????step++;?????//步驟+1??
  • ??????
  • ????if(?n?==?1?)??
  • ????{??
  • ????????Move(?a,?c?);???//將a柱上的一個盤子直接移動到c柱??
  • ????????return?;??????
  • ????}??
  • ????else??
  • ????{??
  • ????????Hanoi_Three(?n-1,?a,?c,?b);?????//將a上n-1個盤子以c為緩存,全部轉移到?b?柱上??
  • ????????Move(?a,?c?);???????????????????//將A上留下的第n個盤子,直接轉移到?C??柱上??
  • ????????Hanoi_Three(?n-1,?b,?a,?c);?????//將b上的n-1個盤子,以a為緩存,全部轉移到?c?柱上??
  • ????}??
  • }??

  • 二、四柱漢諾塔(Hanoi_Four):

    ?

    當柱子為四根時,對于只是將盤子全部轉移到另一根柱子上這個目的來說,是大大降低了難度,而且算法的復雜度也大大降低了。但是,這個時候,如果要你找到一個最優的、步驟最少的實現方法,可以說難度是提升了一個數量級。

    有些人可能會質疑,為什么,我用三柱漢諾塔的思想不是很優化了嗎?

    別急,且讓我慢慢向你道來。

    ?

    先來看看這種‘看上去很合理’的解法:

    假設,A,B,C,D,分別為:源位置,緩存,緩存,目的位置。

    因為三柱的時候,我們是將A的前n-1個盤子放到B上緩存,然后將第n個盤子放到C柱上。

    現在的情況好很多,有兩個可以緩存的柱子,因此,看上去移動起來更加方便,原來B上需要緩存的n-1個盤子,現在可以只是n-2個盤子,而將第n-1個盤子放到C上緩存。

    ?

    具體的流程如下(非最優解法):

    1、從A借助C、D將 n-2個盤子移動到B上。

    2、將第n-1個盤子移動到C上。

    3、將第n個盤子移動到D上。

    4、將第n-1個盤子移動到D上。

    5、從B借助A、C將 n-2個盤子全部移動到D上。

    ?

    看上去,非常完美,筆者也一度覺得這個思想沒有破綻,甚至我還自以為找到了k根柱子漢諾塔的通用方法(想當然的將B柱上緩存的數量從n-2個,改為n-(k-2)個盤子)。直到我看了這篇文章:多柱漢諾塔最優算法設計探究

    ??? 雖然我們想到讓盤子盡量不發生重疊來保證步數的最少,但是這并不能絕對保證。或許在盤子較少的情況下是可行的,但是盤子增多時,那些多余的只有一個盤子的柱子是可以加以利用的(可能的優化在這里)。雖然這么做加多了每次的移動步數,但是卻從另一個側面減少了遞歸的數量,因此我們需要從這里邊找一個平衡點。

    ?

    下面我們來看看,1941年,美國的J. S. Frame,給出的四柱漢諾塔的算法思想,也叫Frame算法

    1、用4柱漢諾塔算法把A柱上部分的n- r個碟子通過C柱和D柱移到B柱上【F( n- r )步】。

    2、用3柱漢諾塔經典算法把A柱上剩余的r個碟子通過C柱移到D柱上【2^r-1步】(參照上述三柱時的情況)。

    3、用4柱漢諾塔算法把B柱上的n-r個碟子通過A柱和C柱移到D柱上【F(n-r)步】。

    4、依據上邊規則求出所有r(1≤r≤n)情況下步數f(n),取最小值得最終解。

    ?

    因此Frame算法的遞歸方程如下:

    F(n)=min(2*F(n-r)+2^r-1),(1≤r≤n)。

    ?

    大家有沒有發現,其實,這個算法思想跟我們之前認為合理的算法基本一致,差別只是在于他將我們的n-2個碟子緩存到B上,改為了將n- r個碟子轉移到B柱上。

    差別即使核心,這個算法的核心,就是計算n個盤子的情況下,r為何值時,能夠使得算法最優。

    ?

    找到了核心,我們現在的任務就明確了,就是對r值的計算。

    這里給出了一個較笨的方法--枚舉(不知道各位有沒有其他方法)。就是將一定范圍內的n與r的所有取值帶入,得到滿足F(n)為最小值的r的值,記為K[n] = r;

    具體的代碼如下:

    [cpp]?view plaincopy
  • void?Init_K(void?)??
  • {??
  • ????int?i,?k;?????
  • ????__int64?temp;?????
  • ????__int64?m[Max+1]?=?{0};???????
  • ??????
  • ????for(?i?=?1;?i?<=?Max;?i++?)??
  • ????{??
  • ????????m[i]?=?INT_MAX;???????
  • ????????for(?k?=?1;?k?<=?i;?k++?)??
  • ????????{??
  • ????????????temp?=?2*m[i-k]?+?(__int64)pow(2,k)?-?1;??????
  • ????????????if(?temp?<?m[i]?)??
  • ????????????{??
  • ????????????????m[i]?=?temp;??????
  • ????????????????K[i]?=?k;?????
  • ????????????????//printf("K[%d]?=?%d,?m[i]?=?%d\n",?i,?k,?temp?);?????
  • ????????????}??
  • ????????}??
  • ????}??
  • }??

  • 得到各個n對于的r之后,算法將變的非常簡單,具體實現如下:

    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<math.h>??
  • #define?Max?100???
  • #define?INT_MAX?0xfffffffffffffff??
  • int?K[Max+1]?=?{0};???
  • int?step?=?0;?????
  • ??
  • void?Hanoi_Four(?int?n,?char?a,?char?b,?char?c,?char?d?);?????
  • void?Hanoi_Three(?int?n,?char?a,?char?b,?char?c?);????
  • void?Move(?char?x,?char?y?);??????
  • ??
  • void?Move(?char?x,?char?y?)??
  • {??
  • ????printf("%c?-->?%c\n",?x,?y);?//打印路徑,x-->y??
  • }??
  • ??
  • void?Hanoi_Three(?int?n,?char?a,?char?b,?char?c?)??
  • {??
  • ????if(?n?<=?0?)??
  • ????????return?;??????
  • ??????
  • ????step++;?????//步驟+1??
  • ??????
  • ????if(?n?==?1?)??
  • ????{??
  • ????????Move(?a,?c?);???//將a柱上的一個盤子直接移動到c柱??
  • ????????return?;??????
  • ????}??
  • ????else??
  • ????{??
  • ????????Hanoi_Three(?n-1,?a,?c,?b);?????//將a上n-1個盤子以c為緩存,全部轉移到?b?柱上??
  • ????????Move(?a,?c?);???????????????????//將A上留下的第n個盤子,直接轉移到?C??柱上??
  • ????????Hanoi_Three(?n-1,?b,?a,?c);?????//將b上的n-1個盤子,以a為緩存,全部轉移到?c?柱上??
  • ????}??
  • }??
  • ??
  • void?Hanoi_Four(?int?n,?char?a,?char?b,?char?c,?char?d?)??
  • {??
  • ????if(?n?<=?0?)??
  • ????????return?;??????
  • ??????
  • ????if(?n?==?1?)??
  • ????{??
  • ????????step++;???
  • ????????Move(?a,?d?);?????
  • ????????return?;??????
  • ????}??
  • ????else??
  • ????{??
  • ????????int?kn?=?K[n];????
  • ????????//printf("kn?=?%d\n",?K[n]);??????
  • ????????Hanoi_Four(?n-kn,?a,?c,?d,?b?);?????//用4柱漢諾塔算法把A柱上部分的n-?kn個碟子通過C柱和D柱移到B柱上??
  • ????????Hanoi_Three(?kn,?a,?c,?d?);?????????//用3柱漢諾塔經典算法把A柱上剩余的kn個碟子通過C柱移到D柱上。??
  • ????????Hanoi_Four(?n-kn,?b,?a,?c,?d?);?????//用4柱漢諾塔算法把B柱上的n-r個碟子通過A柱和C柱移到D柱上??
  • ????}??
  • }??
  • ??
  • void?Init_K(void?)??
  • {??
  • ????int?i,?k;?????
  • ????__int64?temp;?????
  • ????__int64?m[Max+1]?=?{0};???????
  • ??????
  • ????for(?i?=?1;?i?<=?Max;?i++?)??
  • ????{??
  • ????????m[i]?=?INT_MAX;???????
  • ????????for(?k?=?1;?k?<=?i;?k++?)??
  • ????????{??
  • ????????????temp?=?2*m[i-k]?+?(__int64)pow(2,k)?-?1;??????
  • ????????????if(?temp?<?m[i]?)??
  • ????????????{??
  • ????????????????m[i]?=?temp;??????
  • ????????????????K[i]?=?k;?????
  • ????????????????//printf("K[%d]?=?%d,?m[i]?=?%d\n",?i,?k,?temp?);?????
  • ????????????}??
  • ????????}??
  • ????}??
  • }??
  • ??
  • int?main()??
  • {??
  • ????int?n;????
  • ????Init_K();?????
  • ??
  • ????printf("Please?enter?the?number?of?the?Plates:?\n");??
  • ????while(?scanf("%d",?&n)?!=?EOF?)??
  • ????{??
  • ????????step?=?0;?????
  • ????????Hanoi_Four(?n,?'A',?'B',?'C',?'D'?);??????
  • ????????//Hanoi_Three(?n,?'A',?'B',?'C'?);????
  • ????????printf("**************************\nTotal?Step:?%d\n",?step?);????
  • ??
  • ????????printf("Please?enter?the?number?of?the?Plates:?\n");??
  • ????}??
  • ??????
  • ????return?0;?????
  • }??
  • ?

    到這里,四柱漢諾塔的算法基本講完了。

    有興趣的同學,可以繼續歸納多柱漢諾塔的實現方法,歡迎交流指導!

    ?

    ?

    ?很多時候,看似合理的背后,其實是一種思維定勢。。。

    from:?http://blog.csdn.net/cyh_24/article/details/8075578

    《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。