94建中資訊科校內培訓 CK5826 馮俊菘
Dynamic Programming
方法概述
在Divide and Conquer的時候,如果一次會分成數個子問題,很容易就會要
重複計算一些子問題,這樣非常浪費時間。所以我們建一張表,把所有子問題的 答案存下來,下次再碰到時,就可以直接用。這是由上而下的做法。
我們也可以倒過來,由下往上做,就是先把可能遇到的子問題都處理好,
再一步一步推回原本的問題。
用Dynamic Programming,最重要的是「DP元素」和「遞迴式」。「DP元素」
就是表格上每一格存的東西所代表的意義;「遞迴式」就是用子問題答案建構出 原問題答案的方法。通常決定了這兩樣東西,就可以很容易的寫出程式。而這兩 樣東西的好壞,會決定這個演算法的好壞。
如果題目不只求最佳解的值是多少,還要問「如何解」,那多半需要把DP 過程中所做的選擇記錄下來,然後從最後面trace-back回去。
題 1 生產線
現在有兩條生產線,每條線有n個工作站,第a條線上的第b個站需要Aa,b
的時間。每一個貨物都要依序經過n個工作站(無論在哪條線上),才能出廠。
從工作站W1,x到W1,x+1不需要花時間,但是從W1,x到W2,x+1需要T1,x的時間;同
樣的,從W2,x到W1,x+1需要T2,x的時間。進入生產線和從生產線送出分別需要
E1、E2、X1、X2的時間。
給定這些時間,若想以最快的方式生產一件產品,要經過哪些工作站?
DP元素:Time[a, b] 表示 第 a 條生產線第 b 個站到出口所需的最短時間 遞迴式:Time[a, b] = min{ Time[a, b+1], Time[3-a, b+1] + Ta,b }
題 2 Longest Common Subsequence (最長共同子序列)
定義:字串p為字串s的subsequence 若且唯若 p的每個字元都按照順序出現在 s中。(不一定要連續,連續的又稱為substring)例如字串”abc”的subsequence 有 “”、“a”、“b”、“c”、“ab”、“bc”、“ac”、“abc”。
現在給定兩字串s、t,求一字串p,滿足p同時為s及t的subsequence,且p 的長度最長,此時稱p為s與t的LCS。
例:”bronze” 和 ”crown” 的LCS為 ”ron”。
DP元素:len[a, b] 表示 s[1..a] 和 t[1..b] 的 LCS 長度
遞迴式:len[a, b] = max{ len [a-1, b] , len[a, b-1] , len[a-1, b-1] + (s[a] ==
t[b]) }
1/4
94建中資訊科校內培訓 CK5826 馮俊菘
變化:如果要求3個字串以上的LCS呢?
題 3 Longest Incresing Subsequence (最長遞增子序列)
給定一數列,求此數列的一個最長的子序列,且該子序列嚴格遞增。這有很 多種方法,有O(n2) 的,也有O(n lgn) 的。另外,也可以利用LCS來求LIS。
例:{5, 2, 8, 7, 3, 1, 6, 4} 的LIS為 {2, 3, 4} 或 {2,3, 6}。
DP元素:len[a] 表示 結束在 a 的 LIS 長度
遞迴式:len[a] = max{ len[b] | b < a && s[b] < s[a] } + 1
題 4 矩陣相乘
矩陣A[p1, p2] 和 B[p2, p3] 相乘,需要p1*p2*p3次乘法,得到 [p1, p3]的矩陣。
若一系列的矩陣相乘,順序不同,所需乘法的數量不一樣。
像 [1, 3]*[3, 5]*[5, 4],若先乘前兩項,會需要1*3*5 + 1*5*4 = 35次乘法;
若先乘後兩項,則需要3*5*4 + 1*3*4 = 72次乘法。
現在給定n個矩陣的大小,保證一定可乘,求最少需幾次乘法?要怎麼乘?
DP元素:m[a, b] 表示 從矩陣 a 乘到矩陣 b 所需的最少乘法數 遞迴式:m[a, b] = min{m[a, k ] + m[ k+1 , b] + a x*ky*by | a <= k < b}
題 5 最大子矩陣
給定一矩陣m,求一個子矩陣其中的元素和最大。
5-1 一維矩陣
最暴力的做法是O(n3),對每個起點、終點都加一次,求最大值。
用預先累加的pre - processing技巧可以做到O(n2)。
最好的做法是O(n)。
DP元素:sum[a] 表示 結束在 a 的最大子矩陣和 遞迴式:sum[a] = max{ 0 , sum[a-1] } + m[a]
5-2 二維矩陣
窮舉所有可能的起點、終點,並一一算出每個子矩陣的和,再求最大值,這 個方法是O(n6)。
同樣用pre-processing的技巧,可以變成O(n4)。這裡的pre-processing,是讓 m[a, b] 代表 [1, 1] – [a, b] 內的元素和。[a, b] – [c, d] 的子矩陣元素和就等於 m[c, d] – m[c, b-1] – m[a-1, d] + m[a-1, b-1],這樣可以在O(1)的時間得到任意子矩陣 的和。
如果搭配維度壓縮的技巧,可以做到O(n3)。
題 6 Maximal Rectangle
給一個二維的布林矩陣,求一個面積最大的子矩陣,裡面全部都是1。
2/4
94建中資訊科校內培訓 CK5826 馮俊菘
6-1 正方形子矩陣
所求的矩陣必須是正方形,加了這個條件,好做很多。
DP元素:m[a, b] 表示 以 [a, b] 為右下角的最大非 0 子矩陣邊長 遞迴式:m[a, b] = min{ m[a-1, b] , m[a, b-1] , m[a-1, b-1] } + 1
6-2 長方形子矩陣
長方形有不同的長和寬,不能在每一格直接確定哪一種長 方形一定比較好,也不能直接選取面積最大的。如右,若在 (4,
3)的地方選了3*3的長方形,那在 (5, 3) 處就找不到 5*2 的最
大長方形。所以要把每種長寬分開來做。
這裡講的是O(n3) 的方法,還可以更快。用的是pre-processing的技巧。
DP元素:m[a, b, c] 表示 以 [a, b] 為右下角高為 c 的最大非 0 子矩陣的寬 遞迴式:m[a, b, c] = min{ m[a, b-1, c-1] , m[a, b, 1] }
題 7 0-1 背包問題
上次在講的「分數背包」,是物品可以切割的情形。這次的「0-1背包」,就是 指「物品只能拿0個或拿1個,不能切割」。當然,這次不能再greedy了,請看 反例:
背包重量限制:50
編號x 1 2 3
重量Wx 10 20 30
價值Vx 100 150 210
如果用上次那種greedy的方法,會拿{1, 2},價值250,剩下20的重量浪 費掉了。然而最佳解是拿{2, 3},價值360,沒有浪費重量。
DP元素:m[a, b] 表示 在物品 1..a 中拿取總重量 b 能得到的最大價值 遞迴式:m[a, b] = max{ m[a-1, b] , m[a-1, b-Wa] + Va }
題 8 非常速配 (92 北市賽)
給定兩小寫字串(3 ≦ len ≦ 15),請依以下方式計算此兩字串的相似程度。
可以在兩字串的任何位置加入空白,其中一種加入空白的方式使所得分數最大,
問分數最大值為多少?
相同字母1分,不同字母 -0.5分,字母對空白 -0.3分,空白對空白0分。
“aspire” 和 “aspect” 的最高分是2.8分,如左。
“combine” 和 “cancel” 的最高分是1分,如右。
題 9 賣香蕉 (TOI2005 第二次模擬考)
3/4
01110 11111 11111
aspire__
asp__ect
combin_e_
ca___ncel
94建中資訊科校內培訓 CK5826 馮俊菘
有一家賣香蕉的商店,跟一個蕉農簽約:每天用每公斤C元的單價,買進 與前一天相同數量的香蕉。若要再增加,需要額外付每公斤P元的處理費;若當 天沒賣完,可以選擇退貨,需要花每公斤 Q 元的處理費,也可以選擇送給員工 帶回家.。
每天的數量 = 當天本來買進的量 + 額外增加的量 - 退回的量
現在給你 N 天的銷售數量(N<=30)以及C、P、Q,求最小的進貨成本。
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
Dynamic Programming這部分的題目很多,類型也很雜,難度變化很大,
這邊只舉出幾個較簡單的例子。有時候一個題目就有很多種DP的方法,每種方 法所需的時間和空間複雜度也不一樣。這需要多練習,才能靈活運用。還有,實 作也很重要,大家要把這幾次講的題目好好寫一遍,有問題記得要問。
特別強調一點,想要真的學好這門學問,請當一個「獵食者」,而不是「受 食者」。
連續三個禮拜,講了Divide and Conquer、Greedy Method、Dynamic
Programming;市賽、全國賽中需要「技巧」的題目大概脫不出這個範圍(還有一
部分是Graph Theory)。如果比賽中真的想不到解法,就暴力吧!多少都會有點
分數,不要留白。筆試的部分請大家多讀計算機概論,並做點題目,這可能會成 為最後的決勝關鍵喔!
即將出征的校隊們,加油!
4/4