1. 程式人生 > >考研復試之dp重溫

考研復試之dp重溫

any 我們 放置 gfw ron alt http lan 情況下

來自http://cppblog.com/menjitianya/archive/2015/10/23/212084.html

感謝作者!

1??、動態規劃的經典模型 1、線性模型 線性模型的是動態規劃中最常用的模型,上文講到的最長單調子序列就是經典的線性模型,這裏的線性指的是狀態的排布是呈線性的。【例題6】是一個經典的面試題,我們將它作為線性模型的敲門磚。 【例題6】在一個夜黑風高的晚上,有n(n <= 50)個小朋友在橋的這邊,現在他們需要過橋,但是由於橋很窄,每次只允許不大於兩人通過,他們只有一個手電筒,所以每次過橋的兩個人需要把手電筒帶回來,i號小朋友過橋的時間為T[i],兩個人過橋的總時間為二者中時間長者。問所有小朋友過橋的總時間最短是多少。 技術分享圖片
圖二-1-1 每次過橋的時候最多兩個人,如果橋這邊還有人,那麽還得回來一個人(送手電筒), 也就是說N個人過橋的次數為2*N-3(倒推,當橋這邊只剩兩個人時只需要一次,三個人的情況為來回一次後加上兩個人的情況...)。 有一個人需要來回跑,將手電筒送回來(也許不是同一個人,realy?!) 這個回來的時間是沒辦法省去的,並且回來的次數也是確定的,為N-2,如果是我,我會選擇讓跑的最快的人來幹這件事情,但是我錯了... 如果總是跑得最快的人跑回來的話,那麽他在每次別人過橋的時候一定得跟過去,於是就變成就是很簡單的問題了, 花費的總時間: T = minPTime * (N-2) + (totalSum-minPTime) 來看一組數據 四個人過橋花費的時間分別為 1 2 5 10,按照上面的公式答案是19,但是實際答案應該是17。 具體步驟是這樣的: 第一步:1和2過去,花費時間2,然後1回來(花費時間1); 第二歩:3和4過去,花費時間10,然後2回來(花費時間2); 第三部:1和2過去,花費時間2,總耗時17。 所以之前的貪心想法是不對的。 我們先將所有人按花費時間遞增進行排序, 假設前i個人過河花費的最少時間為opt[i], 那麽考慮前i-1個人過河的情況,即河這邊還有1個人,河那邊有i-1個人,並且這時候手電筒肯定在對岸,所以 opt[i] = opt[i-1] + a[1] + a[i] (讓花費時間最少的人把手電筒送過來,然後和第i個人一起過河) 如果河這邊還有兩個人,一個是第i號,另外一個無所謂,河那邊有i-2個人,並且手電筒肯定在對岸,所以 opt[i] = opt[i-2] + a[1] + a[i] + 2*a[2] (讓花費時間最少的人把電筒送過來,然後第i個人和另外一個人一起過河,由於花費時間最少的人在這邊,所以下一次送手電筒過來的一定是花費次少的,送過來後花費最少的和花費次少的一起過河,解決問題) 所以 opt[i] = min{opt[i-1] + a[1] + a[i] , opt[i-2] + a[1] + a[i] + 2*a[2] }
2.區間模型 區間模型的狀態表示一般為d[i][j],表示區間[i, j]上的最優解,然後通過狀態轉移計算出[i+1, j]或者[i, j+1]上的最優解,逐步擴大區間的範圍,最終求得[1, len]的最優解。 【例題7】給定一個長度為n(n <= 1000)的字符串A,求插入最少多少個字符使得它變成一個回文串。 典型的區間模型,回文串擁有很明顯的子結構特征,即當字符串X是一個回文串時,在X兩邊各添加一個字符‘a‘後,aXa仍然是一個回文串,我們用d[i][j]來表示A[i...j]這個子串變成回文串所需要添加的最少的字符數,那麽對於A[i] == A[j]的情況,很明顯有 d[i][j] = d[i+1][j-1] (這裏需要明確一點,當i+1 > j-1時也是有意義的,它代表的是空串,空串也是一個回文串,所以這種情況下d[i+1][j-1] = 0);當A[i] != A[j]時,我們將它變成更小的子問題求解,我們有兩種決策: 1、在A[j]後面添加一個字符A[i]; 2、在A[i]前面添加一個字符A[j]; 根據兩種決策列出狀態轉移方程為: d[i][j] = min{ d[i+1][j], d[i][j-1] } + 1; (每次狀態轉移,區間長度增加1) 空間復雜度O(n^2),時間復雜度O(n^2) 3.背包模型 背包問題是動態規劃中一個最典型的問題之一。由於網上有非常詳盡的背包講解 ,這裏只將常用部分抽出來,具體推導過程詳見 《背包九講》 。 a.0/1背包 有N種物品(每種物品1件)和一個容量為V的背包。放入第 i 種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入背包可使價值總和最大。 f[i][v]表示前i種物品恰好放入一個容量為v的背包可以獲得的最大價值。 決策為第i個物品在前i-1個物品放置完畢後,是選擇放還是不放,狀態轉移方程為: f[i][v] = max{ f[i-1][v], f[i-1][v - Ci] +Wi } 時間復雜度O(VN),空間復雜度O(VN) b.完全背包 有N種物品(每種物品無限件)和一個容量為V的背包。放入第 i 種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入背包可使價值總和最大。 f[i][v]表示前i種物品恰好放入一個容量為v的背包可以獲得的最大價值。 f[i][v] = max{ f[i-1][v - kCi] + kWi | 0 <= k <= v/Ci } (當k的取值為0,1時,這就是01背包的狀態轉移方程) 時間復雜度O( VNsum{V/Ci} ),空間復雜度在用滾動數組優化後可以達到 O( V )。 進行優化後(此處省略500字),狀態轉移方程變成: f[i][v] = max{ f[i-1][v], f[i][v - Ci] +Wi } 時間復雜度降為 O(VN)。 c.多重背包 有N種物品(每種物品Mi件)和一個容量為V的背包。放入第i種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入背包可使價值總和最大。 f[i][v]表示前i種物品恰好放入一個容量為v的背包可以獲得的最大價值。 f[i][v] = max{ f[i-1][v - kCi] + kWi | 0 <= k <= Mi } 時間復雜度O( Vsum(Mi) ), 空間復雜度仍然可以用滾動數組優化後可以達到 O( V )。 優化:采用二進制拆分物品,將Mi個物品拆分成容量為1、2、4、8、... 2^k、Mi-( 2^(k+1) - 1 ) 個對應價值為Wi、2Wi、4Wi、8Wi、...、2^kWi、( Mi-( 2^(k+1) - 1 ) )Wi的物品,然後采用01背包求解。 這樣做的時間復雜度降為O(Vsum(logMi) )。 【例題8】一群強盜想要搶劫銀行,總共N(N <= 100)個銀行,第i個銀行的資金為Bi億,搶劫該銀行被抓概率Pi,問在被抓概率小於p的情況下能夠搶劫的最大資金是多少? p表示的是強盜在搶銀行時至少有一次被抓概率的上限,那麽選擇一些銀行,並且計算搶劫這些銀行都不被抓的的概率pc,則需要滿足1 - pc < p。這裏的pc是所有選出來的銀行的搶劫時不被抓概率(即1 - Pi)的乘積,於是我們用資金作為背包物品的容量,概率作為背包物品的價值,求01背包。狀態轉移方程為: f[j] = max{ f[j], f[j - pack[i].B] * (1-pack[i].p) } 最後得到的f[i]表示的是搶劫到 i 億資金的最大不被抓概率。令所有銀行資金總和為V,那麽從V-0進行枚舉,第一個滿足1 - f[i] < p的i就是我們所要求的被抓概率小於p的最大資金。 4.狀態壓縮模型 5.樹狀模型

【例題11】給定一顆樹,和樹上每個結點的權值,求一顆非空子樹,使得權和最大。

用d[1][i] 表示i這個結點選中的情況下,以i為根的子樹的權和最大值;

用d[0][i]表示i這個結點不選中的情況下,以i為根的子樹的權和最大值;

d[1][i] = v[i] + sum{ d[1][v] | v是i的直接子結點 && d[1][v] > 0 }

d[0][i] = max( 0, max{ max( d[0][v], d[1][v] ) | v是i的直接子結點 } )

這樣,構造一個以1為根結點的樹,然後就可以通過dfs求解了。

這題題目要求求出的樹為非空樹,所以當所有權值都為負數的情況下需要特殊處理,選擇所有權值中最大的那個作為答案。

未完待續。。。

考研復試之dp重溫