算法概論筆記 - 動態(tài)規(guī)劃法

定義一組子問題,按照由小到大慌植,以小問題的解答支持大問題求解的模式蝶柿,依次解決所有的子問題交汤,并最終得到原問題的解答芙扎。

隱含思想

DAG有向無圈圖的拓?fù)渑判?/p>

節(jié)點(diǎn)對應(yīng)于我們定義的子問題,邊表示子問題間的依賴關(guān)系:即如果求解子問題B必須依賴子問題A的解答圈浇,則(概念上)存在一條由A到B的邊磷蜀。

子問題性質(zhì)
存在子問題間的一種排序以及如下的關(guān)聯(lián)關(guān)系:對于任意一個(gè) 子問題,這種關(guān)聯(lián)關(guān)系說明了如何在給定(在排序中)相對其“較小”的子問題的解的前提下收壕,求得該子問題的解

妙處
恰當(dāng)?shù)剡x擇子問題虫埂,使得所有重要的信息都得以保存并便于今后使用

常見子問題模式
模式1

輸入為x1, x2, ..., xn掉伏,子問題為x1, x2, ..., xi供常。

最終子問題數(shù)量將為線性。

模式2

輸入為x1, x2, ..., xn和y1, y2, ..., ym源祈,子問題為x1, x2, ..., xi和y1, y2, ..., yj香缺。

最終子問題數(shù)量為O(m*n)

模式3

輸入為x1, x2, ..., xn,子問題為xi, x(i+1), ..., xj祸轮。

最終子問題數(shù)量為O(n^2)倔撞。

模式4

輸入為樹,子問題為其子樹冕房。

若樹有n個(gè)節(jié)點(diǎn)耙册,則最終子問題數(shù)量為O(nlogn)详拙。

最長遞增子序列

輸入:一個(gè)數(shù)字序列a1蹲诀、a2脯爪、...尚揣、an。

輸出:從以上序列中按順序選出的一個(gè)子集滨巴,并且嚴(yán)格單調(diào)遞增,形如a(i1)熄守、a(i2)裕照、a(ik),其中1<=i1<i2<...<ik<=n负间。

策略1
  1. 為每個(gè)元素建立一個(gè)對應(yīng)的節(jié)點(diǎn)态秧,對任意兩個(gè)存在遞進(jìn)關(guān)系的元素ai和ak(即同時(shí)滿足i<j且ai<ak)愤诱,增加一條連接兩者對應(yīng)節(jié)點(diǎn)的有向邊(i, j)

  2. 形成dag捐友,求遞增子序列問題變?yōu)閷ふ襠ag中的最長路徑

for j = 1,2,...,n:
    L(j) = 1 + max{L(i):(i, j) in E}
return max{L(j)}

L(j)是以序列中j為終點(diǎn)的最長路徑撮慨,即對應(yīng)于最長遞增子序列的長度

實(shí)現(xiàn)

  1. 為方便圖的鄰接表表示砌溺,可變形為
for i = 1,2,...,n:
    for (i, j) in E:
    L(j) = max {L(j), L(i) + 1}
return max{L(j)}

see implement: dp.LongestIncreSub

  1. 求反轉(zhuǎn)圖G的鄰接表表示

此時(shí)無需構(gòu)造原圖G

時(shí)間復(fù)雜度max{O(n^2), O(V+E)}

策略2

子問題:將LCS(i)記做包含

的最長遞增子序列長度鲜棠。

LIS[i] = max{1,LIS[k]+1}培慌,其中吵护,對于任意的k<=i-1,arr[i] > arr[k]雄坪。

最長公共子序列LCS

輸入:兩個(gè)序列X![](http://latex.codecogs.com/svg.latex?(x_0, x_1, x_2, ..., x_m))笨农,Y![](http://latex.codecogs.com/svg.latex?(y_0, y_1, y_2, ..., y_n))。

輸出:一個(gè)序列S任意刪除若干個(gè)字符得到新序列T,則T叫做S的子序列孕豹。兩個(gè)序列X和Y的公共子序列中十气,長度最長的那個(gè),定義為X和Y的最長公共子序列芹枷。

策略
子問題:將LCS(i, j)記做![](http://latex.codecogs.com/svg.latex?(x_0, x_1, x_2, ..., x_i))與![](http://latex.codecogs.com/svg.latex?(y_0, y_1, y_2, ..., y_j))的最長公共子序列長度鸳慈。

考察

绩郎,若![](http://latex.codecogs.com/svg.latex?x_i = y_j)彼念,則![](http://latex.codecogs.com/svg.latex?LCS(i, j) = LCS(i-1, j-1)+1)哲思。否則![](http://latex.codecogs.com/svg.latex?LCS(i, j) = max {LCS(i-1, j), LCS(i, j-1)})


![](http://latex.codecogs.com/svg.latex?LCS(i, j)=\begin{cases}0 & if ; i=0 ; or ; j=0\LCS(i-1, j-1)+1 & if ; i>0, j>0, and ; x_i = x_j\max {LCS(i-1, j), LCS(i, j-1)} & if ; i>0, j>0, and x_i != x_j\end{cases})

時(shí)間復(fù)雜度max{O(n^2)}

變體1:最長公共子串

子序列不要求子序列中的字符在原序列中連續(xù)壳快,而子串要求連續(xù)凛驮。

策略
子問題:![](http://latex.codecogs.com/svg.latex?L(i, j))表示以

為結(jié)尾的相同子串的最大長度.

考察

裆站,若![](http://latex.codecogs.com/svg.latex?x_i = y_j),則![](http://latex.codecogs.com/svg.latex?L(i, j) = L(i-1, j-1)+1)黔夭。否則![](http://latex.codecogs.com/svg.latex?L(i, j) = 0)


![](http://latex.codecogs.com/svg.latex?L(i, j)=\begin{cases}0 & if;i=0;or;j=0\L(i-1, j-1)+1 & if;i>0, j>0, and ; x_i = x_j\0 & if ; i>0, j>0, and x_i != x_j\end{cases})

在上述過程中記錄![](http://latex.codecogs.com/svg.latex?L(i, j))的最大值宏胯,最后即可得到最長公共子串的長度

時(shí)間復(fù)雜度O(n^2)

最長公共子串類似:最大子串和

PAT1007. Maximum Subsequence Sum

輸入:給定一個(gè)序列X![](http://latex.codecogs.com/svg.latex?(x_0, x_1, x_2, ..., x_m))。

輸出:找出該序列具有最大和的子串本姥。如果該序列所有數(shù)均為負(fù)數(shù)肩袍,則輸出0。

策略
子問題:

表示以
為結(jié)尾的子串的最大和婚惫。

考察

氛赐,若
,則
對于
毫無幫助,即![](http://latex.codecogs.com/svg.latex?Sum(i) = x_i)速蕊,否則![](http://latex.codecogs.com/svg.latex?Sum(i) = x_i + Sum(i-1))


![](http://latex.codecogs.com/svg.latex?Sum(i)=\begin{cases}x_i & if ; i=0 ; or ; Sum(i-1)<=0\x_i + Sum(i-1) & if ; Sum(i-1)>0\end{cases})

在上述過程中記錄

的最大值趋急,并根據(jù)第一種情況重新修改tempLeft(當(dāng)前子串左邊開始位置)。最后即可得到最大子串和以及最大子串牲芋。

時(shí)間復(fù)雜度O(n)

空間復(fù)雜度O(1)

算法過程中只需存儲上一步的Sum和位置信息

變體2:最長遞增子序列LIS
  1. 對輸入序列X進(jìn)行排序,得到序列Y
  2. 求解序列X和Y的最長公共子序列捺球,即是序列X的最長遞增子序列

時(shí)間復(fù)雜度O(n^2)

編輯距離

隨意插入空隙“-”到每個(gè)字符串中使兩個(gè)字符串對齊缸浦,對于該種對齊方式,代價(jià)為兩個(gè)字符串對應(yīng)字母不相同的列數(shù)氮兵。如:

S - N O W Y
S U N N - Y

SNOWY和SUNNY該種對齊方式的代價(jià)為3

編輯距離是指兩個(gè)字符串的各種對齊所可能具有的最小代價(jià)裂逐。

策略
子問題:定義E(i, j)為尋找兩個(gè)字符串x[1...i]與y[1...j]之間的編輯距離。
由于要將E(i, j)表示為較之更小的子問題的表達(dá)式泣栈,我們考慮x[1...i]與y[1...j]所有對齊中最右側(cè)的列的可能情況:

  1. x[i]與-
  2. -與y[j]
  3. x[i]與y[j]
    因此卜高,E(i, j) = min{1+E(i-1, j), 1+E(i, j-1), diff(x[i], y[j])+E(i-1, j-1)}

當(dāng)x[i]=y[j]時(shí),diff()取0南片;否則取1

所有子問題E(i, j)的解構(gòu)成一個(gè)二維表篙悯,要保證求解順序(E(i-1, j), E(i, j-1)和E(i-1, j-1)總是在E(i, j)之前求解)

算法如下:

for i = 0, 1, 2 ... m:
    E(i, 0) = i
for j = 1, 2 ... n:
    E(0, j) = j
for i = 1, 2 ... m:
    for j = 1, 2 ... n:
        E(i, j) = min{E(i-1, j)+1, E(i, j-1)+1, E(i-1, j-1)+diff(i,j)}
return E(m, n)

see implement: dp.EditingDistance
時(shí)間復(fù)雜度為O(m*n)

擴(kuò)展
在二維表中,令{(i-1, j-1)->(i, j) : x[i]=y[j]}中邊的長度置為0铃绒,并將其他所有邊的長度置為1鸽照。則求編輯距離問題變?yōu)榍骴ag中的最短路徑,即點(diǎn){0,0}與{m,n}之間的最短路徑颠悬。

在該路徑上矮燎,向下的移動表示刪除定血,向右為插入,而對角線移動表示匹配或者替換诞外。

背包問題

一共有n件物品澜沟,分別重w1,w2, ..., wn,價(jià)值v1,v2,...,vn峡谊。背包最多能裝W磅茫虽,如何組合才能使背包攜帶的價(jià)值最高既们。

廣泛應(yīng)用于需要機(jī)遇有限資源進(jìn)行選擇判斷的領(lǐng)域

多副本的背包問題

每種物品的數(shù)量無限
1. 子問題:考慮容量較小的背包
定義K(w) = 容量w可以容納的最高價(jià)值
若K(w)的最優(yōu)解包含物品i濒析,將物品i去掉,則會留下K(w-wi)的最優(yōu)解啥纸。不知道包含哪些i号杏,因此嘗試所有的可能
![](http://latex.codecogs.com/svg.latex?K(w) = max_{i:w_i<=w} {K(w-w_i)+v_i})

K(0) = 0
for w = 1 to W:
    K(w)= max{K(w-w(i))+v(i):wi<=w}
return K(W)

時(shí)間復(fù)雜度O(nW)

see implement: dp.bag.MultiBagProWithCapa

構(gòu)造DAG
針對每個(gè)w構(gòu)造節(jié)點(diǎn),其中w in 0~W斯棒。對于每個(gè)節(jié)點(diǎn)與每個(gè)物品盾致,使用該物品的容量確定邊的終點(diǎn),使用該物品的價(jià)值確定邊的權(quán)值荣暮,可以構(gòu)造出一個(gè)DAG庭惜。求背包所能容納的最高價(jià)值最終歸結(jié)為尋找該DAG的最長路徑。

2. 子問題:考慮較少的物品種類
TODO

單副本的背包問題

每種物品都只有一件
策略
在K(w)子問題中包含關(guān)于哪件物品已經(jīng)被使用過的信息穗酥。
定義子問題K(w, j) = 基于背包容量w和物品1, ..., j所能得到的最高價(jià)值
用更小的子問題表示K(w, j):
![](http://latex.codecogs.com/svg.latex?K(w, j) = max(K(w-w_j,j-1)+v_j, K(w, j-1)))

initialize all K(0, j) = 0 and all K(w, 0) = 0
for j = 1 to n:
    for w = 1 to W:
        if w(j) > w: K(w, j) = K(w, j-1)
        else: K(w, j) = max{K(w, j-1), K(w-w(j), j-1)+v(j)}

時(shí)間復(fù)雜度O(nW)

see implement: dp.bag.SingleBagPro

矩陣鏈?zhǔn)较喑?/h5>

一個(gè)mn的矩陣與一個(gè)np的矩陣相乘护赊,約需要進(jìn)行mnp次乘法。通過在矩陣鏈?zhǔn)较喑斯降牟煌恢貌迦肜ɑ∶陨龋覀兛梢缘玫胶芏嗖煌挠?jì)算方式百揭,那么哪種乘法次序代價(jià)最兴ァ蜓席?
自然的表示
滿二叉樹:每個(gè)矩陣對應(yīng)一個(gè)葉節(jié)點(diǎn),樹根為最終的乘積课锌,而樹的內(nèi)部節(jié)點(diǎn)表示中間過程的部分乘積厨内。各種可能的乘法次序?qū)?yīng)不同的滿二叉樹。

如果一個(gè)樹最優(yōu)渺贤,那么其子樹必然也最優(yōu)

策略
假設(shè)我們需要計(jì)算

其中每個(gè)矩陣的維數(shù)分別為![](http://latex.codecogs.com/svg.latex?m_0m_1, m_1m_2, ..., m_{n-1}m_n)
定義![](http://latex.codecogs.com/svg.latex?C(i, j) = the ; minimum ; cost ; of ; computing A_i
A_{i+1}...A_j)
C(i, j)可分割為C(i, k)和C(k+1, j)兩個(gè)子問題雏胃,即
![](http://latex.codecogs.com/svg.latex?C(i, j) = min_{i<=k<j}[C(i,k) + C(k+1, j) + m_{i-1}m_km_j]?)

由于C(i, k)的維數(shù)為

,C(k+1, j)的維數(shù)為

求解順序:當(dāng)求解到某個(gè)子問題時(shí)志鞍,比該子問題規(guī)模小的子問題已被求解。

因?yàn)?i,j)坐標(biāo)并不在(i+1, j)坐標(biāo)的下邊或右邊固棚,此時(shí)無法按照從上至下仙蚜,從左至右的求解順序

for i = 1 to n: C(i, i) = 0
for s = 1 to n-1:
    for i = 1 to n-s:
        j = i+s
        C(i, j) = min{C(i,k) + C(k+1, j) + m(i-1)*m(k)*m(j):i<=k<j}
return C(1, n)

see implement: dp.MatrixChain

時(shí)間復(fù)雜度O(n^3)

動態(tài)規(guī)劃 VS 遞歸記憶

記憶:遞歸算法記住之前的調(diào)用結(jié)果

  • 優(yōu)點(diǎn):記憶只會求解那些實(shí)際被用到的子問題
  • 缺點(diǎn):遞歸所具有的的間接開銷通常較高厂汗,其大O符號所包含的常數(shù)因子相對而言較大
寫在最后
  • 立個(gè)Flag,TODO will be done some day娶桦。
  • 渣代碼,且輕噴?:worried:?衷畦。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市霎匈,隨后出現(xiàn)的幾起案子戴差,更是在濱河造成了極大的恐慌,老刑警劉巖铛嘱,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖释,死亡現(xiàn)場離奇詭異,居然都是意外死亡墨吓,警方通過查閱死者的電腦和手機(jī)球匕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帖烘,“玉大人亮曹,你說我怎么就攤上這事∶刂ⅲ” “怎么了照卦?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乡摹。 經(jīng)常有香客問我役耕,道長,這世上最難降的妖魔是什么聪廉? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任瞬痘,我火速辦了婚禮,結(jié)果婚禮上板熊,老公的妹妹穿的比我還像新娘框全。我一直安慰自己,他們只是感情好干签,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布津辩。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喘沿。 梳的紋絲不亂的頭發(fā)上情萤,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機(jī)與錄音摹恨,去河邊找鬼筋岛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛晒哄,可吹牛的內(nèi)容都是我干的睁宰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼寝凌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了较木?” 一聲冷哼從身側(cè)響起伐债,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤峰锁,失蹤者是張志新(化名)和其女友劉穎虹蒋,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峭竣,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡皆撩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年毅访,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盘榨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片草巡。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡山憨,死狀恐怖郁竟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蓖议,我是刑警寧澤勒虾,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布修然,位于F島的核電站愕宋,受9級特大地震影響掏婶,放射性物質(zhì)發(fā)生泄漏潭陪。R本人自食惡果不足惜依溯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一黎炉、第九天 我趴在偏房一處隱蔽的房頂上張望慷嗜。 院中可真熱鬧,春花似錦薇溃、人聲如沸沐序。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铣口,卻和暖如春脑题,著一層夾襖步出監(jiān)牢的瞬間叔遂,已是汗流浹背争剿。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工哩掺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涩笤,地道東北人蹬碧。 一個(gè)月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓恩沽,卻偏偏與公主長得像罗心,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子疾瓮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容