2020-09-1310:42:28
@
19世紀的時候,法國數學家愛德華·盧卡斯創造了一個叫漢諾塔的神話:佛教大神梵天在創造世界的時候有點無聊,順便造了三根金剛石柱子,其中第一根柱子上堆了64塊黃金圓盤。梵天命令僧侶把所有圓盤從第一根柱子移動到第三根柱子上,且每次只能移動一片,小圓盤必須在大圓盤的上面。
梵天對僧侶說,如果全部把圓盤搬完,世界將會毀滅,所有的佛塔、廟宇、僧侶都將在烈火中化為灰燼。
僧侶搬完所有圓盤,需要多長時間?這個問題可以用遞歸算法來求解。
遞歸
遞歸算法在程序設計中被廣泛應用。根據度娘的解釋,遞歸,就是函數直接或間接地調用函數自身,直到引用對象可知。(有點像現在流行的“套娃”梗)

遞歸有一個好處,就是可以把復雜的步驟簡化成幾個簡單的步驟,從而實現對復雜問題的一步步拆解。
比如,在漢諾塔游戲中,要把n個圓盤按上述規則從A柱子移動到C柱子上,我們可以按三個大步驟去做:
1、先把上面的n-1個圓盤移動到B柱子;

2、把第n個(即最底層的那個)圓盤移動到C柱子;

3、最后把n-1個圓盤從B柱子移動到C柱子,就完成了。

而回到第一個步驟,怎么把n-1個圓盤按規則移動到B柱子上呢?可以繼續進行拆解,先把n-2個圓盤移動到C柱子上,然后把第n-1個圓盤移動到B柱子上,最后把n-2個圓盤從C柱子移動到B柱子……
這樣一直拆解下去,最終就可以分解為每次只移動一個圓盤的步驟了。
拆解的流程如下:




![]()
於是,就有這樣的結論:

回到最初的問題,如果僧侶需要把64個圓盤從第一根柱子移動到第三根柱子,需要搬動(2^64-1)次,假設每秒鍾搬動一次,共需要5800億年。
1 /*漢諾塔遞歸算法*/ 2 #include <stdio.h> 3 void move(int n,char x,char y) 4 { 5 printf("%c-->%c\n",x,y); 6 } 7 void hanota(int n,char A,char B,char C) 8 //一共n個盤子,要把這n個盤子借助B柱子從A柱子全部移到C柱子 9 { 10 if(n==1)//遞歸出口,也就是結束的標志 11 { 12 move(n,A,C);//當只有一個盤子的時候,直接從A柱子移到C柱子 13 } 14 else 15 { 16 hanota(n-1,A,C,B);//當n>1時,把(n-1)個盤子借助C柱子從A柱子移到B柱子 17 move(n,A,C);//然后把第n個盤子從A柱子移到C柱子 18 hanota(n-1,B,A,C);//再把(n-1)個盤子借助A柱子從B柱子移到C柱子 19 } 20 } 21 //主函數 22 int main() 23 { 24 int m; 25 char a='A',b='B',c='C'; 26 scanf("%d",&m);//輸入有幾個盤子 27 hanota(m,a,b,c); 28 return 0; 29 }
