從 Fibonacci 數列看「動態規劃」思想

2022-02-23 17:07:57 字數 2825 閱讀 2768

在資料結構中,最經典的演算法/問題是:floyd 演算法(最短路徑)、哈夫曼編碼和 fibonacci(斐波那契數列),揹包問題等等。但當時,這些經典僅僅是描述了乙個問題的解決方法,沒有對整個這類問題更深入的闡述。

而事實上,隨著對問題理解深入,發現這些演算法和問題都包含了「動態規劃」的思想。在此思想基礎上,對這些演算法和問題可以進行重大改進——演算法更簡單、時間複雜度更小。

「動態規劃(dynamic programming,dp)」對每個子問題只求解一次,將其結果儲存在一張表中,從而避免每次遇到各個子問題時重新計算。「programming」是指一種規劃,在這裡以及線性規劃中,都是指使用一種**化的解法,而不是指寫計算機**。

下面用 c# 演示斐波那契數列的一般遞迴演算法,以及利用「動態規劃」思想的改進演算法。

namespace fibonacci
;
static

void main(string args)

///
/// 時間複雜度 o(n!)
/// 

/// 

/// 

static

int fibonacci(int n)

///
/// 時間複雜度 o(n)
/// 

/// 

/// 

/// 

static

int fibonacci_dp(int n, ref

int m)

}
}

其中,fibonacci方法是斐波那契數列一般的遞迴演算法。而fibonacci_dp方法是利用「動態規劃」思想的演算法。

從時間複雜度上看,一般的遞迴演算法是o(n!),呈指數級增長。而採用「動態規劃」思想的演算法只有o(n)

n=5時,fibonacci(5)的計算過程如下:

fib(4) + fib(3)
(fib(3) + fib(2)) + (fib(2) + fib(1))
((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
(((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))
可以看出,這個遞迴演算法,對每個子問題都要重新計算。而實際上,若利用「動態規劃」思想這是沒必要的。對於已經計算完的子問題,下次再遇到直接使用。將已經計算的結果儲存在陣列m中,在後面直接使用,避免重複計算。

在實際開發中,了解一些演算法方面的知識,往往很有必要。能夠分析自己的演算法,比如你的演算法在何種輸入規模,效率是較高的。

個人覺得,在開發 erp 系統時,會涉及很多演算法。最近寫乙個關於改變工廠生產過程中變更加工工藝(客戶稱為「工藝再造」)的遞迴演算法,猛然發現,滿複雜的。當時有點驚訝。之前,除了上學時《資料結構》裡的經典演算法和典型問題外,思考得並不多。

下面是大概說明一下「動態規劃」思想。

採用「動態規劃」方法解決最優化問題中的兩個要素:最優子結構和重疊子問題。

最優子結構。子問題的最優解是問題的乙個最優解。當乙個問題具有最優子結構時,提示我們動態規劃可能會適用。

子問題重疊。用來解原問題的遞迴演算法可反覆地解同樣的子問題,而不是總在產生新的子問題。

動態規劃思想可分為如下 4 個步驟:

描述最優解的結構。

遞迴定義最優解的值。

按自底向上的方式計算最優解的值。

由計算出的結果構造乙個最優解。

第 1~3 步構成問題的動態規劃解的基礎。第4步在只要求計算最優解的值時可以略去。如果的確要做第 4 步,則有時要在第 3 步的計算中記錄一些附加資訊,使構造乙個最優解變得容易。

「動態規劃」是運籌學的乙個分支,是求解決策過程(decision process)最優化的數學方法。20 世紀 50 年代初,美國數學家 r.e.bellman 等人在研究多階段決策過程(multistep decision process)的優化問題時,提出了著名的最優化原理(principle of optimality),把多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解,創立了解決這類過程優化問題的新方法——動態規劃。1957 年出版了他的名著《dynamic programming》,這是該領域的第一本著作。

動態規劃在經濟管理、生產排程、工程技術和最優控制等方面得到了廣泛的應用。

雖然,動態規劃主要用於求解以時間劃分階段的動態過程的優化問題,但一些與時間無關的靜態規劃,如線性/非線性規劃,只要人為地引進時間因素,視為多階段決策過程,也可以用動態規劃方法求解。

動態規劃方法是解最優化問題的一種途徑和方法,而不是乙個特定演算法。針對一種最優化問題,由於各種問題的性質不同,往往確定最優解的條件也不相同。也就不存在一種萬能的動態規劃演算法。因此,必須具體問題具體分析處理,以豐富的想象力去建立模型,用創造性的技巧去求解。

動態規劃 Fibonacci數列

概要 斐波那契數列 fibonacci sequence 又稱 分割數列 因數學家列昂納多 斐波那契 leonardoda fibonacci 以兔子繁殖為例子而引入,故又稱為 兔子數列 指的是這樣乙個數列 1 1 2 3 5 8 13 21 34 在數學上,斐波那契數列以如下被以遞推的方法定義 f...

Fibonacci數列(動態規劃相關)

問題描述 fibonacci數列的遞推公式為 fn fn 1 fn 2,其中f1 f2 1。當n比較大時,fn也非常大,現在我們想知道,fn除以10007的餘數是多少。輸入格式 輸入包含乙個整數n。輸出格式 輸出一行,包含乙個整數,表示fn除以10007的餘數。樣例輸入 10樣例輸出 55樣例輸入 ...

計算Fibonacci數列

上機內容 用動態分配空間的方法計算fibonacci數列的前30項並儲存到動態分配的空間中 上機目的 學習fibonacci數列演算法 我的程式 includeusing namespace std void main int p new int 30 p 1 p 1 1 cout p p 2 fo...