動態規劃詳解

2022-06-05 20:27:06 字數 1701 閱讀 4791

其實根本就談不上詳解,應該說只是隨便談談,真正能詳解動態規劃的又有幾個人,所以,這個標題略顯扯淡。

前段時間一直在做關於資料結構的題,也算是對資料結構有了一定的了解,知道了有些資料結構的基本演算法。現在剛剛開始接觸動態規劃,其實寫這篇文章的初衷是一來鍛鍊一下自己的總結能力,二來也是希望通過這篇文章,來指引和我一樣的初學者,廢話不多說了,開始吧。

一、

01揹包

我最開始接觸的有關動態規劃的是01揹包,這應該也是動態規劃入門最好的了吧。 01揹包是很簡單的問題,當然也不乏一些變種讓你絞盡腦汁也想不到,這裡我們不討論那些,我只說最簡單的。

假設有n種物品,每種都只有乙個,第i種物品的體積為vi,重量為wi,選一些物品到乙個容量為c的揹包,使得揹包內總物品的體積不超過c的情況下重量最大。

因為每種東西只有放入揹包和不放入兩種狀態,這也就是01的由來了。對於這個問題,你當然可以列舉所有的可能性,如果有n個物品的話,總共有2^n種可能性,如果資料大的話,普通計算機是不可能計算的,當然你可以借一台超級計算機,這是另外一種情況,不予討論。

我們可以換一種思考方法,對與第i件物品,我們比較把它放入和不放入揹包中的重量比較,取最大值,這樣我們就可以得到這樣乙個表示式 dp(v) = max(dp(v), dp(v-vi) + wi), 具體實現我們可以採用遞迴的方式。這樣時間複雜度好會不會好很多,很明顯不會,因為會重複計算好多次,舉個簡單例子,如果我們計算dp(6),在這個過程中我們用到了dp(3),而在計算dp(5)的過程中也用到了dp(3),這樣這兩個過程就會重複計算一次dp(3),想想資料量大的話該有多少重複啊。。

關於這個重複計算的問題,我們只要在過程中記錄這些結果就完全可以避免重複計算,還是上面的例子,我們在dp(6)中計算了dp(3),並且將dp(3)的結果儲存了,在dp(5)中我們直接呼叫dp(3),就行了,這種方法被稱為記憶化搜尋,因為dp()這個函式你在一定程度上可以把它當做dfs()。

雖然記憶話搜尋就是動態規劃的思想,不過這還不是最好的方法,我們完全可以把遞迴改成遞推的方式,這樣dp[v] = max(dp[v], dp[v-vi] + wi),這個表示式也被稱為狀態轉移方程,這也是動態規劃的核心,還有,一定要理解01揹包這個方程,因為絕大多數狀態轉移方程是由它演變來的。

我們不難寫出遞推的**

for (int i = 1; i <= n; i++)

}

時間複雜度為o(n*n),時間上我們沒辦法在優化了,但在空間上我們可以繼續優化,我們可以把dp陣列改成一維的,得到以下**也是正確的,因為在求解的過會覆蓋掉一部分,但覆蓋之後的值卻是該狀態的最優解。

for (int i = 1; i <= n; i++)

}

二、最長非降子串行

這個也比較簡單,也是基本的東西,不過越基本的越應該熟悉。

我們讓dp[i] 儲存前i個數的最長非降子串行長度,每次計算以第i個數結尾的最長子序列的長度。狀態轉移方程就是dp[i] = max(dp[i],dp[j] + 1)。

#include #include int a[100];

int dp[100];

int max(int a, int b)

int main()

}printf("%d\n",dp[n]);

}

三、最長公共子串行

此文章將持續更新。。。。。。

動態規劃詳解

從一道題目出發 求兩個字串的最大公共子串長度,比如字串str1 bdcaba和字串str2 abcbdab的最大公共子串即為紅色部分bcba,長度為4 如何從動態規劃的思想出發解題呢,動態規劃的特點是當前最優解是從之前的子最優解和當前狀態分析得到,是一種遞推的過程,比如上述最大公共子串,對於長度為n...

《動態規劃》 ACM 動態規劃例題詳解

描述 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 圖1 圖1給出了乙個數字三角形。從三角形的頂部到底部有很多條不同的路徑。對於每條路徑,把路徑上面的數加起來可以得到乙個和,你的任務就是找到最大的和。注意 路徑上的每一步只能從乙個數走到下一層上和它最近的左邊的那個數或者右邊的那個數。輸...

動態規劃詳解(2)

接下來,讓我們來看看如何解決二維的dp問題。問題描述 平面上有n m個格仔,每個格仔中放著一定數量的蘋果。你從左上角的格仔開始,每一步只能向下走或是向右走,每次走到乙個格仔上就把格仔裡的蘋果收集起來,這樣下去,你最多能收集到多少個蘋果。解這個問題與解其它的dp問題幾乎沒有什麼兩樣。第一步找到問題的 ...