Michael Tsai 2012/10/4
台大資訊鐵條回收公司
長度 1 2 3 4 5 6 7 8 9 10
價錢 1 5 8 9 10 17 17 20 24 30
回收鐵條, 依長度算錢.
假設你有一條很長的鐵條, 長度為n (n為正整數)
可以把長鐵條砍成長度為整數的短鐵條
請問如何砍才能夠用這條鐵條換到最多錢?
價目表
長度為4的鐵條
長度 1 2 3 4 5 6 7 8 9 10
價錢 1 5 8 9 10 17 17 20 24 30 價目表
9 1 8
5 5 1 1 1 1
1 1 5 1 5 1 5 1 1
8 1
長度為n的鐵條
長度為n的鐵條, 共有幾種要檢查的?
每一整數的地方都可以選擇要切, 或不切
共有n-1個”缺口”
因此需要檢查2𝑛−1種組合
Θ(2𝑛−1) 口吐白沫…
長度為n的鐵條
讓情況變少種一點
如果我們規定鐵條只能越砍越大或一樣, 則需要 檢查的不同方式可用partition function來表示
大約為𝑒𝜋 2𝑛3
4𝑛 3 種
仍然為指數(比任何n的多項式都長得快)
定義一些符號
𝑝𝑖: 長度為i的鐵條賣價(不再繼續砍)
𝑟𝑛: 長度為n的鐵條的最高賣價(最佳化砍法)
如果長度為n的鐵條最佳化砍法把鐵條砍成k段
𝑛 = 𝑖1 + 𝑖2 + ⋯ + 𝑖𝑘
𝑟𝑛 = 𝑝𝑖1 + 𝑝𝑖2 + ⋯ + 𝑝𝑖𝑘
類divide-and-conquer思維
“我請我的遞迴朋友們來解大小較小但同樣的問 題”
“假設我知道比較小的問題答案, 如何得出這個 問題的答案?”
𝑟 𝑛 = max(𝑝 𝑛 , 𝑟 1 + 𝑟 𝑛−1 , 𝑟 2 + 𝑟 𝑛−2 , … , 𝑟 𝑛−1 + 𝑟 1 )
不砍刀 這一刀砍在左邊數過來第i個
𝑟𝑖=? 𝑟𝑛−𝑖=?
最後再看哪個砍法為可得到最大值即為解.
Optimal Substructure
Optimal solutions to a problem incorporate
optimal solutions to related subproblems, which we may solve independently.
𝑟 𝑛 = max(𝑝 𝑛 , 𝑟 1 + 𝑟 𝑛−1 , 𝑟 2 + 𝑟 𝑛−2 , … , 𝑟 𝑛−1 + 𝑟 1 )
𝑟𝑖=? 𝑟𝑛−𝑖=?
稍微調整一下
把subproblem數目變少一點
𝑟 𝑛 = max
1≤𝑖≤𝑛 (𝑝 𝑖 + 𝑟 𝑛−𝑖 )
𝑝𝑖 𝑟𝑖=?
這一段砍下來就不再砍
成更小的了(拿去賣) 這一段是subprogram, 找遞迴朋友去解
Cut-Rod v0.1 alpha
Cut_Rod(p,n) if n==0
return 0 q=-∞
for i=1 to n
q=max(q, p[i]+Cut_Rod(p,n-i)) return q
猜猜看, 她會喜歡嗎?
n每增加1, 時間大約x2
Recursion tree
4
3
2 1 0
1 0 0
0
2 1 0
1 0 0
0
同樣的事情做那麼多遍…浪費時間!
遞迴式又來拉~
𝑇 0 = 1
𝑇 𝑛 = 1 + 𝑛−1𝑗=0 𝑇(𝑗)
結果:
T 𝑛 = 2𝑛 (如我們所料)
<Homework when you have time> :P
Exercise 15.1-1
假如我們有點記性的話…
空間換取時間
做過的事情就不要再做
“記得結果”就好: 填表與查表
Dynamic programming: 這裡的 programming指填表, 不是寫程式
當
所有不同的subprogram數目是 polynomial, 及
解掉subprogram的時間也是 polynomial,
dynamic programming方法可以在 polynomial time內完成
Dynamic programming的做法
Top-down with memoization
還是用遞迴的方式來做
但是每次做之前就先檢查是不是做過一樣的
如果沒做過就遞迴下去, 但是要記錄結果
如果做過就用查表取得之前的結果
Bottom-up method
把所有的subprogram從小排到大
然後從小排到大來解
解一個subproblem時候, 所有它所需要的 subsubproblem都已經被解完了
請問哪一個快?
課本p.365有答案.
Cut-Rod v0.1 beta (Top-down)
Memoized_Cut_Rod(p,n)
let r[0..n] be a new array for i=0 to n
r[i]=-∞
return Memoized_Cut_Rod_Aux(p,n,r)
Memoized_Cut_Rod_Aux(p,n,r) if 𝑟 𝑛 ≥ 0
return r[n]
if n==0 q=0 else q=-∞
for i=1 to n
q=max(q,p[i]+Memoized_Cut_Rod_Aux(p,n-i,r)) r[n]=q
return q
p: 價目表 n: 鐵條長度
p: 價目表 n: 鐵條長度 r: 存最佳解的陣列
Cut-Rod v0.1 gamma (Bottom-up)
Bottom_Up_Cut_Rod(p,n)
let r[0..n] be a new array r[0]=0
for j=1 to n q=-∞
for i=1 to j
q=max(q,p[i]+r[j-i]) r[j]=q
return r[n]
Θ 𝑛2
Subproblem graphs
4
3
2 1 0
1 0 0
0
2 1 0
1 0 0
0
4
3
2 1 0
Bottom-up method: Reverse Topological Sort Subproblem x必須要考慮subproblem之 optimal solution <x,y> directed edge
Top-down method: Depth First Search
Subproblem graphs
Subproblem graph的大小讓我們可以估計 dynamic programming演算法的執行時間
大小?
𝐺 = 𝑉, 𝐸 . 我們指 𝐸 和 𝑉 .
𝐸 =有幾個要解的subproblem (因為有記結果, 所以一個subproblem只要做一次)
|𝑉|=每個subproblem需要幾個比它小的 subproblem的結果
大致的估計: 和 𝐸 和 𝑉 成線性
最後的小問題
剛剛的程式只把可以拿多少錢算出來
沒有真的印出要怎麼切
如何解決?
用另外一個陣列(大小Θ(𝑛))紀錄optimal solution 應該切的大小.
最後依序印出結果即可.
課本p. 369有解答.
連串矩陣相乘問題
Matrix multiplication is associative.
(( A1𝐴2 𝐴3)𝐴4)
( A1 𝐴2𝐴3 )𝐴4
A1𝐴2 𝐴3𝐴4
𝐴1( 𝐴2𝐴3 𝐴4)
𝐴1 𝐴2 𝐴3𝐴4
以上算出來答案都一樣
𝐴1 𝐴2 𝐴3 𝐴4 …… 𝐴𝑛
題目: 求𝐴1𝐴2 … 𝐴𝑛矩陣相乘之解.
𝐴1.cols=𝐴2.rows
𝐴1and 𝐴2are compatible.
連串矩陣相乘問題
Matrix-Multiply(A,B) if A.columns != B.rows
error “incompatible dimensions”
else let C be a new A.rows x B.cols matrix for i=1 to A.rows
for j=1 to B.cols 𝑐𝑖𝑗=0
for k=1 to A.cols 𝑐𝑖𝑗 = 𝑐𝑖𝑗 + 𝑎𝑖𝑘 ∙ 𝑏𝑘𝑗 return C
主要花費時間在這邊!
𝐴 𝐵
p q
共花費pqr次乘法的時間
看一個例子
𝐴1𝐴2 𝐴3 花費之乘法數目=10 × 100 × 5 + 10 × 5 × 50 = 7500
𝐴1 𝐴2𝐴3 花費之乘法數目=100 × 5 × 50 + 10 × 100 × 50 = 75000
差十倍!!
10
100 100 5
5
50
連串矩陣相乘問題-正式版
給一連串的矩陣 𝐴1, 𝐴2, … , 𝐴𝑛 , 其中矩陣𝐴𝑖的大 小為𝑝𝑖−1 × 𝑝𝑖 (𝑖 = 1, 2, … , 𝑛), 找出一種乘法可 以使計算時的乘法數目最少
沒有真的要算結果, 而只是找出能最快算出結果 的方法.
因為算”怎麼算比較快”多花的時間, 比”用爛方 法直接算”多花的時間少很多
暴力法有多暴力
全部到底有幾種算法呢?
用遞迴定義:
(n)之解為Catalan numbers, Ω 4𝑛
𝑛32 , or is also Ω 2𝑛
𝑃 𝑛 =
1
𝑃 𝑘 𝑃(𝑛 − 𝑘)
𝑛−1 𝑘=1
if 𝑛 = 1, if 𝑛 ≥ 2.
假設先這樣分: 𝐴1𝐴2 … 𝐴𝑘 𝐴𝑘+1𝐴𝑘+2 … 𝐴𝑛
所以不耍暴力了.
使用dynamic programming
正規步驟:
1. 找出最佳解的”結構”
2. 使用遞迴來定義最佳解的花費
3. 計算最佳解的花費
4. 使用已經計算的資訊來構築最佳解
找出最佳解的”結構”
總花費=𝐴𝑖. . 𝐴𝑘的花費+𝐴𝑘+1. . 𝐴𝑗的花費+把𝐴𝑖. . 𝐴𝑘和𝐴𝑘+1. . 𝐴𝑗 乘起來的花費
最佳解的結構: 假設有𝐴𝑖. . 𝐴𝑗的最佳解, 此一方法為在k切一刀.
則在此𝐴𝑖. . 𝐴𝑗最佳解中, 𝐴𝑖. . 𝐴𝑘的相乘方法一定是𝐴𝑖. . 𝐴𝑘的最 佳相乘方法
假設𝐴𝑖. . 𝐴𝑘不是最佳解, 則我們可以在𝐴𝑖. . 𝐴𝑗中把𝐴𝑖. . 𝐴𝑘換成 更好的方法, 則可以找到一個更好的𝐴𝑖. . 𝐴𝑗的相乘方法矛盾.
子問題的最佳解可以導出大問題的最佳解!
最後結論: 分成兩個子問題, 並嘗試所有可以切分的地方(k值)
𝐴𝑖𝐴𝑖+1… 𝐴𝑘 𝐴𝑘+1𝐴𝑘+2… 𝐴𝑗
𝑖 ≤ 𝑗
𝑖 ≤ 𝑘 < 𝑗 在k切一刀
使用遞迴來定義最佳解的花費
遞迴定義:使用子問題最佳解的cost來定義大問 題最佳解的cost
定義: 𝑚[𝑖, 𝑗]為𝐴𝑖. . 𝐴𝑗所需花的最少乘法數
𝐴𝑖..𝑘𝐴𝑘+1..𝑗所花乘法數=𝑝𝑖−1𝑝𝑘𝑝𝑗
𝐴𝑖..𝑘 𝐴𝑘+1..𝑗
𝐴𝑖.rows=𝑝𝑖−1
𝐴𝑘.cols=𝑝𝑘
𝐴𝑘+1.rows=𝑝𝑘
𝐴𝑗.cols=𝑝𝑗
使用遞迴來定義最佳解的花費
𝑚 𝑖, 𝑗 = 𝑚 𝑖, 𝑘 + 𝑚 𝑘 + 1, 𝑗 + 𝑝𝑖−1𝑝𝑘𝑝𝑗
但是我們不知道最佳解中的k的值
因此我們必須找所有𝑘 = 𝑖, 𝑖 + 1, … , 𝑗 − 1
最後版本:
𝑚 𝑖, 𝑗 = 0
𝑖≤𝑘<𝑗
min {𝑚 𝑖, 𝑘 + 𝑚 𝑘 + 1, 𝑗 + 𝑝
𝑖−1𝑝
𝑘𝑝
𝑗} if 𝑖 = 𝑗,
if 𝑖 < 𝑗.
計算最佳解的花費
純recursive解法: exponential time
使用前面教的Bottom-up填表方法: 每個不同的 subprogram僅需解1次
有幾個不同的問題?
1 ≤ 𝑖 ≤ 𝑗 ≤ 𝑛, 幾個i和j的組合?
答案: 𝑛
2 + n = Θ 𝑛2
𝑖 ≠ 𝑗 𝑖 = 𝑗
計算最佳解的花費
如何決定填表的順序呢? (這次有i,j兩個變數)
𝑚 𝑖, 𝑗 = 0
𝑖≤𝑘<𝑗min {𝑚 𝑖, 𝑘 + 𝑚 𝑘 + 1, 𝑗 + 𝑝𝑖−1𝑝𝑘𝑝𝑗} if 𝑖 = 𝑗, if 𝑖 < 𝑗.
𝑘 − 𝑖 + 1個矩陣相乘 𝑗 − 𝑘個矩陣相乘 都小於𝑗 − 𝑖 + 1個
我們可以把j-i+1(也就是要相乘的matrix個數) 當作problem size的定義
n=p.length-1
let m[1..n,1..n] and s[1..n-1,2..n] be new tables
for i=1 to n m[i,i]=0 for l=2 to n
for i=1 to n-l+1 j=i+l-1
m[i,j]=∞
for k=i to j-1
q=m[i,k]+m[k+1,j]+pi−1𝑝𝑘𝑝𝑗 if q<m[i,j]
m[i,j]=q s[i,j]=k return m and s
大problem的解只會用到小problem的解.因此慢慢往上長.
邊界條件先設好.
把同樣problem size的所有i,j組合都依序做過
使用遞迴式找出最佳切點k
Θ(𝑛3)
計算最佳解的花費
用一個例子來trace code比較快
Matrix 𝑨𝟏 𝑨𝟐 𝑨𝟑 𝑨𝟒 𝑨𝟓 𝑨𝟔
Dimension 30 x 35 35 x 15 15 x 5 5 x 10 10 x 20 20 x 25
使用已經計算的資訊來構築最佳 解
前面只印出了花費, 不是真正的解
怎麼乘才是最後的解
使用s陣列的資訊
使用已經計算的資訊來構築最佳 解
Print-Optimal-Parens(s,i,j) if i==j
print 𝐴𝑖 else
print “(“
Print-Optimal-Parens(s,i,s[i,j]) Print-Optimal-Parens(s,s[i,j]+1,j)
print “)”
看了兩個例子以後…
問: 一個問題要有什麼要件才能使用dynamic programming?
答:
1. Optimal substructure
2. Overlapping Subproblems
什麼是Optimal substructure?
Definition: A problem exhibits
optimal substructure if an
optimal solution to the problem contains within it optimal
solutions to subproblems.
怎麼尋找optimal substructure呢?
怎麼尋找optimal substructure呢?
1. 要得到問題的解答有許多選擇(砍在哪邊, 切在哪 邊), 而做這個選擇之後, 我們有一些subproblem要 解決.
2. 我們假設對於一個問題, 我們可以找到那個選擇
3. 知道這個選擇以後, 我們找出哪個subproblem可以 被拿來應用, 及剩下的問題(沒有對應到subproblem 的)怎麼解決
4. 證明大問題的最佳解中可以直接應用(剪下貼上)子 問題的最佳解.
Optimal substructure越簡單越好
𝑟𝑖=? 𝑟𝑛−𝑖=?
𝑝𝑖 𝑟𝑖=?
這一段砍下來就不再砍
成更小的了(拿去賣) 這一段是subproblem, 找遞迴朋友去解 versus
Optimal substructure越簡單越好
𝐴1𝐴𝑖+1… 𝐴𝑘 𝐴𝑘+1𝐴𝑘+2 … 𝐴𝑗
1 ≤ 𝑗
1 ≤ 𝑘 < 𝑗
在k切一刀 假設把問題定義成𝐴1 … 𝐴𝑗就好 (少一個變數)
此為一個子問題 此不為一個子問題!
除非k一直都是j-1, 否則…
Optimal substructure的變化
1. 原始問題的最佳解用了多少個子問題
2. 大問題有多少選擇(選擇用不同的子問題們來 獲得最佳解)
大略來說, 以上兩者決定dynamic programming algorithm的執行時間.
(之前說的Subproblem graphs是另外一種算法)
多少個子問題 有多少選擇 執行時間
鐵條資源回收 Θ(𝑛) n 𝑂 𝑛2
連串矩陣相乘 Θ(𝑛2) n-1 𝑂 𝑛3