初學者如何理解遞迴

2022-08-26 18:27:17 字數 3296 閱讀 3593

0 遞迴的定義

如果你沒明白遞迴的定義,參見本文"0.遞迴的定義"

1 從斐波那契數列開始

斐波那契的遞推公式

斐波那契數列遞迴演算法和遞推公式類似

int fibo(int

x)

就這麼簡單?沒錯,通過這個例子可以看出,遞迴函式只需要寫兩部分,乙個是遞迴終止條件(if(x<3) return 1;),乙個是遞迴的「交接」(return fibo(x-1)+fibo(x-2);)

然而這個遞迴有一點問題,時間複雜度是o(fibo(n))的,因為實際上這個演算法每次呼叫到遞迴終止條件,都只會給答案加1,如果要計算fiibo(n)則必須乙個乙個地加,也就是說要加fibo(b)次

問題出在**呢?

這是fibo(6)的遞迴樹可以發現fibo(1)被呼叫了3次,fibo(2)被呼叫了5次,fibo(3)被呼叫了3次...

看起來沒毛病,實際上不難發現對於同乙個數x,只要計算過一遍,就沒必要再算第二遍,這就是這個演算法浪費時間的地方

2.優化

int ans[202

];int fibo(int

x)int

main()

花一點記憶體作為代價,換來的是o(n)的時間複雜度

加方框表示已經算過一次的,可以直接出結果,無需繼續遞迴

把已經算過的資料「記住」,下一次再次使用的時候可以直接讀取「記憶」,這就是所謂的記憶化

3.數字三角形

傳送門:

這是動態規劃入門題目

設dp[x][y]為從第x行第y列走到底部的最優解

val[x][y]表示第x行第y個數

則如果x不等於n

dp[x][y]=

val[x][y]+max(dp[x+1][y],dp[x+1][y+1])//遞迴「交接」,在動態規劃裡叫做狀態轉移

如果x=n

dp[x][y]=val[x][y]//遞迴終止條件

不難寫出遞迴演算法

#include #include 

#include

#include

const

int n=1003

;int

val[n][n],dp[n][n];

intn;

int solve(int x,int

y)int

main()

4.漢諾塔在印度,有這麼乙個古老的傳說:在世界中心貝拿勒斯(在印度北部)的聖廟裡,一塊黃銅板上插著三根寶石針。印度教的主神梵天在創造世界的時候,在其中一根針上從下到上地穿好了由大到小的64片金片,這就是所謂的漢諾塔。

不論白天黑夜,總有乙個僧侶在按照下面的法則移動這些金片,一次只移動一片,不管在哪根針上,小片必在大片上面。當所有的金片都從梵天穿好的那根針上移到另外一概針上時,世界就將在一聲霹靂中消滅,梵塔、廟宇和眾生都將同歸於盡。

好吧...不得不說這個故事很蛋疼

問題來了,假設移動一次需要一秒鐘,那麼從開始移動到世界毀滅,需要多少時間?

我們首先**一下如何毀滅世界

先蛋疼地把上面的63片從第一根針移動到第二根針(不管中間過程,只關心結果:63片金片移動到了第二根針上)

現在最大的那一片已經在最上面了,直接把它拿到第三根針上就可以了

然後再無比蛋疼地把那63片從第二根針上移到第三根針上(依然不用管中間過程),於是世界就這麼蛋疼地毀滅了(boom!)

下乙個問題就是如何移動那63片

先把最上面62片從第一根針移到第三根針

然後把第63片移到第二根針

再把62片從第三根針移到第二根針

不難看出,只要知道如何移動n片,就可以知道如何移動n+1片

如果n=1,那就無需繼續遞迴,可以直接移動

設f(n)是移動n片所需的步數

那麼f(n)=f(n-1)*2+1

f(n-1)*2是因為要把n-1片移動到乙個「輔助針」上

+1是因為要移動第n片一次

利用高中的知識(也可以找規律),就可以有遞推公式得出通項公式

f(n)=2n-1

f(64)=264-1=18446744073709551615

程式設計師對這個數應該不陌生,剛好是unsigned long long 的上限(這讓我想起來上帝是個程式設計師的理論)

5.聰明的學生

乙個叫獸

,有三個學生,而且三個學生均非常聰明!

一天叫獸

給他們出了乙個題,叫獸

在每個人腦門上貼了一張紙條並告訴他們,每個人的紙條上都寫了乙個正整數,且某兩個數的和等於第三個!(每個人可以看見另兩個數,但看不見自己的)

叫獸會輪流詢問三個人是否已經確定自己頭上的數字

當有學生已經確定自己頭上的數字時,遊戲結束

問題就是,給出三個學生頭上的數,求叫獸詢問多少次的時候遊戲結束

不妨站在學生丙的角度考慮

你現在能看見另外兩個同學的數字,並且認為自己的數字有兩種情況

假設甲和乙頭上的數字分別是3和6,那麼你頭上的數字就可能是3或9(6-3或6+3)

叫獸問甲,你知不知道你頭上的數字?

他說,不知道

叫獸又問乙,乙也說不知道

這時候你就在想,如果你頭上的數字是3,那麼乙就會看到兩個3,由於每個人頭上的數字都是正整數,不可能是零,那麼乙就可以確定他是6

但乙並沒有確定,說明你頭上的數字不是3,是9

於是當叫獸

問你的時候,你說你確定你頭上的數字是9

丙之所以可以知道自己的數字,是因為他假設的錯誤情形會在第二次詢問時結束,但第二次詢問的時候還沒有結束,於是並排除了錯誤的情況

縱觀全域性,三個人都會假設兩種情況,其中一種是與實際情況一致的,另一種是與實際情況不一致的

當且僅當乙個人的錯誤假設被排除,遊戲結束

如果計算出三個人的錯誤假設的結束時間,就可以得出遊戲結束的時間

如何計算三個人的錯誤假設的結束時間?遞迴!

遞迴終止條件:如果一種情況下,兩個人頭上的數字一樣,那麼那個數字與另外兩個人不一樣的人第一次被詢問時就會確定自己的數字

初學者 遞迴

program xuexi3 implicit none integer,external fact 呼叫函式需要寫external 待定 integer n write n read n write fact n stop endrecursive integer function fact n ...

初學者如何理解網路協議

網路協議是什麼?協議分層是怎麼回事?什麼是協議的實現?回想當年初識網路協議,被一張網路層次模型圖中的 物理層 資料鏈路層 網路層 傳輸層 搞得雲裡霧裡。花了很長時間才搞明白網路協議大概是怎麼回事,甚至己經做出了幾個網路程式,但仍感覺對網路協議的本質認識還不夠清楚。一直在思考這些問題,突然有一天,我發...

Dijkstra 演算法 初學者理解

dijkstra演算法 一.該演算法的背景和目的 迪傑斯特拉演算法 dijkstra 是由荷蘭計算機科學家狄克斯特拉於1959 年提出的,因此又叫狄克斯特拉演算法。是從乙個頂點到其餘各頂點的最短路徑演算法,解決的是有權圖中最短路徑問題。迪傑斯特拉演算法主要特點是從起始點開始,採用貪心演算法的策略,每...