思想與性質
首先,動態規劃最重要的是掌握他的思想,動態規劃的核心思想是把原問題分解成子問題進行求解,也就是分治的思想。
那麼什麼問題適合用動態規劃呢?我們通過乙個現實中的例子,來理解這個問題。大家可能在公司裡面都有一定的組織架構,可能有高階經理、經理、總監、組長然後才是小開發,今天我們通過這個例子,來講講什麼問題適合使用動態規劃。又到了一年一度的考核季,公司要挑選出三個最優秀的員工。一般高階經理會跟手下的經理說,你去把你們那邊最優秀的3個人報給我,經理又跟總監說你把你們那邊最優秀的人報給我,經理又跟組長說,你把你們組最優秀的三個人報給我,這個其實就動態規劃的思想!
首先是重疊子問題,不同的問題,可能都要求1個相同問題的解。假如a經理想知道他下面最優秀的人是誰,他必須知道x,y,z,o,p組最優秀的人是誰, 甲總監想知道自己下面最優秀的人是誰,也要去知道x,y,z組裡面最優秀的人是誰?這就有問題重疊了,兩個人都需要了解x,y,z三個小組最優秀的人。
其次是最優子結構,最優解肯定是有最優的子解轉移推導而來,子解必定也是子問題的最優解。甲總監下面最優秀的3個人肯定是從x,y,z提交上來的3份名單中選擇最優秀的三個人。例如q哥是x組長下面的第5名,那麼他肯定不可能是甲總監下面最優秀的三個。
第三是無後效性,這個問題可能比較難理解,也就是求出來的子問題並不會因為後面求出來的改變。我們可以理解為,x組長挑選出三個人,即便到了高階經理選出大部門最優秀的三個人,對於x組來說,最優秀的還是這3個人,不會發生改變。 過程
動態規劃問題,大致可以通過以下四部進行解決。
1.劃分狀態,即劃分子問題,例如上面的例子,我們可以認為每個組下面、每個部門、每個中心下面最優秀的3個人,都是全公司最優秀的3個人的子問題
2.狀態表示,即如何讓計算機理解子問題。上述例子,我們可以使用f[i][3]表示第i個人,他手下最優秀的3個人是誰。
3.狀態轉移,即父問題是如何由子問題推導出來的。上述例子,每個人大leader下面最優秀的人等於他下面的小leader中最優秀的人中最優秀的幾個。
4.確定邊界,確定初始狀態是什麼?最小的子問題?最終狀態又是什麼。例如上述問題,最小的子問題就是每個小組長下面最優秀的人,最終狀態是整個企業,初始狀態為每個領導下面都沒有最優名單,但是小組長下面擁有每個人的評分。
經典模型
1.線性模型
最經典的問題就是斐波那楔數列的問題,每個數的值都是乙個狀態,可以用f[i]表示表示第i個數的值是多少。每個數都是由f[i-1]+f[i-2]轉移而來。
另外乙個經典的問題就是最長上公升自序列(lis),有一串串行,要求找出它的一串子串行,這串子序列可以不連續,但必須滿足它是嚴格的單調遞増的且為最長的。把這個長度輸出。示例:1 7 3 5 9 4 8 結果為4。
我們非常容易表示他的狀態,我們用f[i]表示以第i個數結尾的,最大的上公升自序列是多少?那麼它是怎麼轉移的呢?非常容易想到肯定是從左邊的的數轉移而來,能轉移的數滿足什麼條件呢?肯定是比a[i]更小的。
線性模式還可以拓展成二維問題,例如揹包問題,用f[i][j]表示前i個物品,湊成大小為j的揹包,最大的價值是多少。
這類問題非常的多,但是思路都是這樣,無非就是從左往右,從上到下,從低維到高維進行轉移。
2.區間模型
對於每個問題,都是由子區間推導過來的,我們稱之為區間模型,下面是乙個例子。
我們有乙個連續的序列,每個序列上面都是乙個數字c[i],每次我們都能夠消滅乙個連續的回文子串行,消滅之後左右會合併,成為乙個新序列,問最少需要多少次才能夠把整個序列消滅掉。回文就是從左到有從右到左讀到的序列都是一樣的。
題目比較抽象,我們通過一些例子來說明這個問題吧?例如一開始的序列是1 4 4 2 3 2 1,那麼我們最少需要2次,先消滅掉4 4 , 然後再消滅調1 2 3 2 1.
第二個例子是 1 2 3 4 5 5 3 1,我們先消滅掉2 然後再消滅掉4, 最後消滅 1 3 5 5 3 1, 需要3次。
我們經常用f[i][j]來表示消滅i,j區間需要的代價,文末有鏈結詳細敘述這個問題,大家感興趣的可以看一看。
3.樹狀模型
我們在資料結構樹上面進行最求最優解、最大值等問題,上述我們講的這個績效考核就是乙個樹狀模型,具體不再累敘。
實現的套路
我們實現動態規劃演算法,常用的是2個實現套路,乙個是自底向上,另外乙個是自頂向下。無論是何種方式,我們都要明確動態規劃的過程,把狀態表示、狀態轉移、邊界都考慮好。
1.自底向上,簡單來說就是根據初始狀態,逐步推導到最終狀態,而這個轉移的過程,必定是乙個拓撲序。如何理解這個拓撲序問題呢,甲總監下面有x,y,z兩個小組,甲總監不會一拿到x組最優秀的三個人,就立馬去跟a經理匯報,而是要等到y,z小組也選出來之後,也就是自己下面所有子問題都解決了,才會繼續向匯報。如果推導的過程不是乙個拓撲序,那麼要麼得到錯誤的結果,要麼演算法就要退化。
自底向上一般用來解決什麼問題呢?那就是可以輕鬆確定拓撲序的問題,例如線性模型,都是從左往右進行轉移,區間模型,一般都是從小區間推導到大區間。自底向上的乙個經典實現是斐波那楔數列的遞推實現,即f[i] = f[i - 1] + f[i - 2] 。
2.自頂向下,也就是從最終狀態出發,如果遇到乙個子問題還未求解,那麼就先求解子問題。如果子問題已經求解,那麼直接使用子問題的解,所以自頂向下動態規劃又有乙個形象生動的名字,叫做記憶化搜尋,一般我們採用遞迴的方式進行求解。
自頂向下,我們一般用在樹上面,因為我們根據父親結點,很容易找到所有的子問題,也就是所有的子結點,而自底向上的話,我們要去統計這個結點的所有兄弟結點是否已經實現。會稍微複雜一點,而且比較難理解。
無論是自頂向下還是自底向上,都只是**實現的一種套路,隨便你採用哪乙個,都是可以解的,只是看你的選擇而已。
動態規劃演算法
一 動態規劃演算法原理 將待求解的問題分解成若干個相互聯絡的子問題,先求解子問題,然後從這些子問題的解得到原問題的解 對於重複出現的子問題,只在第一次遇到的時候對它進行求解,並把答案儲存起來。了不去求解相同的子問題,引入乙個陣列,把所有子問題的解存於該陣列中,這就是動態規劃所採用的基本方法。動態規劃...
動態規劃演算法
動態規劃 通過把原問題分解為相對簡單的子問題來求解複雜問題。動態規劃常常適用於有重疊子問題和最優子結構性質的問題。演算法總體思想 演算法的基本步驟 演算法的基本要素 最優子結構 重疊子問題 備忘錄方法 問題描述 子串行 公共子串行 最長公共子串行 lcs 問題 問題分析 動態規劃求解lcs問題 最長...
動態規劃演算法
動態規劃演算法的思路 動態規劃法即 dynamic programming method dp 是系統分析中的種常用方法。動態規劃法是20世紀50年代由貝爾曼 r.bellman 等人提出的,用來解決多階段決策過程問題的一種最優化方法。多階段決策過程是指把研究問題分成若干個相互聯絡的階段,由每個階段...