演算法之動態規劃DP

2021-09-02 14:57:49 字數 2845 閱讀 1484

若要解乙個給定問題,我們可以解其不同部分(即子問題),再根據子問題的解以得出原問題的解。通常許多子問題非常相似,為此動態規劃法試圖僅僅解決每個子問題一次,從而減少計算量:一旦某個給定子問題的解已經算出,則將其記憶化儲存,以便下次需要同乙個子問題解之時直接查表。這種做法在重複子問題的數目關於輸入的規模呈指數增長時特別有用。

最優子結構性質:如果問題的最優解所包含的子問題的解也是最優的,我們就稱該問題具有最優子結構性質(即滿足最優化原理)。最優子結構性質為動態規劃演算法解決問題提供了重要線索。

無後效性。即子問題的解一旦確定,就不再改變,不受在這之後、包含它的更大的問題的求解決策影響。

子問題重疊性質。子問題重疊性質是指在用遞迴演算法自頂向下對問題進行求解時,每次產生的子問題並不總是新問題,有些子問題會被重複計算多次。動態規劃演算法正是利用了這種子問題的重疊性質,對每乙個子問題只計算一次,然後將其計算結果儲存在乙個**中,當再次需要計算已經計算過的子問題時,只是在**中簡單地檢視一下結果,從而獲得較高的效率。

講得再多不如分析一些常用問題,順帶描述一下解題思路。動態規劃最重要的是找到動態轉移方程,將原問題拆分成子問題

例項一(斐波那契數列(fibonacci polynomial)):

斐波那契數列: 後一位數等於前兩位數的和 (如:0 1 1 2 3 5 8 13 …)

狀態轉移方程:f(n) = f(n-1) + f(n-2)

如果使用遞迴解法(自頂向下):

function fib(n)

if n = 0 or n = 1

return n

return fib(n − 1) + fib(n − 2)

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

1. fib(5)

2. fib(4) + fib(3)

3. (fib(3) + fib(2)) + (fib(2) + fib(1))

4. ((fib(2) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

5. (((fib(1) + fib(0)) + fib(1)) + (fib(1) + fib(0))) + ((fib(1) + fib(0)) + fib(1))

由上面可以看出,這種演算法對於相似的子問題進行了重複計算,沒有用到動態規劃的重疊子結構性質,並不是一種高效的演算法。實際上,該演算法的運算時間是指數級增長的。 改進的方法是,我們可以通過儲存已經算出的子問題的解來避免重複計算(自底向上):

array map [0...n] = 

fib(n)

if(map m does not contain key n)

m[n] := fib(n − 1) + fib(n − 2)

return m[n]

將前 n個已經算出的數儲存在陣列map中,這樣在後面的計算中可以直接應用前面的結果,從而避免了重複計算。演算法的運算時間變為 o(n)

例項二(最大子串行和):

最大子串行和:求解乙個序列裡連續子串行的最大和。例如:的最大子串行為,最大子串行和為10。

網上很多都是直接給出乙個動態轉移方程:f(n) = max,可能會有點迷惑。這裡給出我自己的一點理解:

首先,最大和子串行的特點會滿足首元素不為負數,如果第乙個元素為負數,完全可以去掉第乙個元素。

f(n)並不是直接表示最大子串行和,f(n)是表示包含n這個元素的最大子串行和,也就是以n元素結尾的最大和。

根據特點1,將子串行劃分開幾部分。當某f(i)<0時,最大子串行和只能出現在前部分或者後半部分。示例中f(2) = 就是劃分點。

**實現:

//動態規劃,狀態方程 f(i) = max; f(i)表示已a[i]結尾的最大和

public static int maxsubsequence(int array)

//找到maxsum中的最大值

int maxsum = integer.min_value;

for (int i = 0; i < containneleseqsum.length; i++)

}return maxsum;

}

例項三(m球n層樓測臨界值問題)

**實現(對於空間和時間需要進行優化,這裡只是基本思想):

/**

* 用m球測n層樓的臨界值問題:

* m球n層樓,b(m,n) = min },其中b(1,n)=n,b(2,1)=1,1<=k<=n

* 時間複雜度為o(n^3)

** tips:

* 還有乙個簡單的解題方法:

* 以等差數列遞減扔蛋,例如:

* 2球100層樓問題,先從15樓扔,再從29樓,42樓,,,這樣(依此15,14,13,,,)

* 取巧解法:

* 等差數列和》=n,那就是最佳值

* (k+1)k/2>=100 , k為正整數 ===> k=14 所以最優為扔14次

** @param eggs 總的蛋數

* @param floors 總的樓層數

* @return 最小次數

*/public static int findegg(int eggs,int floors)

if(eggs==1)

int res = new int[floors];

for (int k=1;k<=floors;k++)

//取全部k樓對應的結果裡的最小次數即是最優解

int min = res[0];

for(int reselem:res)

}return min;

}

演算法筆記之動態規劃 DP

寫在前面 因為演算法課上駱老師講的是真的好,所以對動態規劃還是比較熟悉的。總結來說就是自底向上求解,主要在於dp轉移方程的分析,然後構造dp陣列進行填表即可,有時可能需要注意儲存求解路徑。動態規劃 簡單分析乙個最大連續子串行之和問題 給定k個整數的序列,其任意連續子串行可表示為,其中 1 i j k...

動態規劃(DP)演算法

動態規劃 dynamic programming,dp 在選擇dp演算法的時候,往往是在決策問題上。動態規劃先解決子問題,再逐步解決大問題。一般情況下,我們能將問題抽象出來,並且問題滿足無後效性,滿足最優子結構,並且能明確地找出狀態轉移方程的話,dp是很好的選擇。無後效性指的是,只要得出了當前狀態,...

基礎演算法之動態規劃 數字DP

數字dp一般用來統計乙個區間 l,r l,r l,r 中滿足條件f i f i f i 的數的個數。條件f i 條件 f i 條件f i 一般與數的大小無關,而與數的組成有關 即數字,個位 十位 百位 因此數的大小對複雜度的影響很小。數字dp本質是對暴力列舉的優化,使得新的列舉方式滿足dp性質,從而...