Alg3 (Org)

advertisement
貪婪演算法
與
動態規劃演算法
短視近利與深謀遠慮
江振瑞
3.1 貪婪演算法基本概念
2
貪婪解題策略



貪 婪 演 算 法 (greedy algorithm) 使 用 貪 婪 策 略 (greedy
strategy)解決問題。
假設一個問題可以藉由一系列的選擇(或決策)來解決,貪
婪演算法的特性為每一次選擇皆採取區域最佳解(locally
optimal solution),而透過每一個區域最佳解最後綜合成
為全域最佳解(globally optimal solution)而將問題解決。
換句話說,貪婪演算法一步步地建構出一個問題的完整解
答。其每一步都藉由貪婪解題策略選擇當下最好的部份解
答加入完整解答中以解決問題。
3
使用貪婪解題策略的演算法





背包(Knapsack)演算法
Huffman編碼演算法
Kruskal最小含括樹演算法
Prim最小含括樹演算法
Dijkstra最短路徑演算法
4
3.2 背包演算法
5
背包演算法背景介紹


背包演算法(knapsack algorithm)使用貪婪
解題策略解決背包問題(knapsack problem)
或稱為零碎背包問題(fractional knapsack
problem)
以下我們先定義背包問題
6
定義 -- 背包問題



給定一個最大載重容量(capacity)為m的背
包,以及n個可以放入背包的物品,其中第i
個物品的重量為wi>0,價格為pi>0
目標: 找出x1,…,Xn以最大化
w x
i
1i  n
i
i
m
限制條件為 1in
其中 0xi1, 1  i  n
i
p x
7
背包演算法
Algorithm 背包演算法
Input: 背包的最大容量m,以及可以放入背
包的n個物品的非負重量wi與價格pi
Output: 介於0與1之間的x1,…,xn分別代表第1
個,…,第n個物品放入背包中的零碎部份。可
wixi  m 。
i

以最大化  pi x,並且滿足
1i  n
1i  n
1: 將pi/wi由大至小排序。
2: 根據此排序來將物品依序盡可能地放入背
8
包中,直至背包容量m用完為止。
背包演算法時間複雜度

行1: 依pi/wi由大至小排序: O(n log n)

行2: 將物品依序放入背包: O(n)
總時間複雜度: O(n log n)
9
背包演算法範例

給定:
n = 3, m = 5, (w1, w2, w3) = (1, 2, 3)
(p1, p2, p3) = (20, 60, 45)

貪婪策略解答:
p1/w1 = 20/1 = 20
p2/w2 = 60/2 = 30
p3/w3 = 45/3 = 15
最佳解: x2 = 1, x1 = 1, x3 = 2/3
最大總價值: 601+201+45(2/3)=110
10
定義 -- 0/1背包問題



給定一個最大載重容量(capacity)為m的背
包,以及n個可以放入背包的物品,其中第i
個物品的重量為wi>0,價格為pi>0
目標: 找出x1,…,Xn以最大化
w x
i
1i  n
i
i
m
限制條件為 1in
其中 xi=0 or xi=1, 1  i  n
i
p x
11
0/1背包演算法範例

給定:
n = 3, m= 5, (w1, w2, w3) = (1, 2, 3)
(p1, p2, p3) = (20, 60, 45)


貪婪策略解答:
p1/w1 = 20/1 = 20
p2/w2 = 60/2 = 30
p3/w3 = 45/3 = 15
解答: x2 = 1, x1 = 1, x3 = 0
總價值: 601+201+450=80
最佳解: x1 = 0, x2 = 1, x3 = 1
總價值: 200+601+451=105
12
背包演算法與
0/1背包演算法範例圖示
13
3.3 Huffman編碼演算法
14
Huffman編碼
字元編碼(character coding)可以分為



固定長度編碼: 如ACSII、Unicode
可變長度編碼: Huffman code
Huffman編碼以字首碼(prefix code)方式達到
字元編碼最佳資料壓縮(optimal data
compression)



字首碼 (prefix code): 任何字元編碼一定不是其他
字元編碼的字首(prefix)。
可以使用二元樹來呈現,達到簡單編碼(encoding)
15
與解碼(decoding)的功能。
Huffman編碼範例


假設給定一個僅用到a, b, c, d, e五個字元的文件,
現在欲針對五個字元進行編碼,以下是可能的固定
長度編碼與可變長度的Huffman字首碼。
字首碼讓出現頻率較高字元的編碼較短,以達到使
用最少位元就可以將所有資料儲存的目標。
a
b
c
14%
17%
23%
6%
40%
固定長度編碼
000
001
010
011
100
可變長度編碼
1111
110
10
1110
0
出現頻率
d
e
16
對應不同編碼的樹及其成本
樹T的成本( 單一字元編碼成本)
Cost(T)   f (c)d T (c)
cC
Cost(T)=3
Cost(T)=2.17
17
Huffman編碼演算法
Algorithm Huffman編碼演算法
Input: 字元集合C與每個字元的出現頻率f
Output: Huffman編碼樹
1.
2.
3.
4.
5.
6.
7.
8.
9.
n  |C| //C: the set of n characters
Q  C //Q: 優先佇列,以字元頻率為優先次序
for i  1 to n – 1 //n個字元(節點)欲合併成一個節點,每迭代合併一次可少一節點
配置一個新的樹節點u
u.left  x  GetMin(Q)
u.right  y  GetMin(Q)
u.f  x.f + y.f
Insert u into Q
return GetMIN(Q) 作為Huffman編碼樹的樹根
18
Huffman編碼演算法時間複雜度


行2: O(n)建立優先佇列Q
行3-8: for迴圈一共執行n-1次,而且迴圈中
的優先佇列操作均為O(log n)複雜度,因此
整個迴圈具有O(n log n)的複雜度
總時間複雜度: O(n log n)
19
Huffman編碼演算法的執行範例
20
Huffman編碼演算法的執行範例(續)
21
Huffman編碼演算法的執行範例(續)
22
Huffman編碼演算法的執行範例(續)
23
Huffman編碼演算法的執行範例(續)
(4)
24
3.4 Kruskal最小含括樹演算法
25
最小含括樹




最小含括樹(Minimum Spanning Tree,
MST)可以定義在歐式空間(Euclidean space)
或者一個圖(graph)上。
給定一個加權連通無向圖(weighted connected
undirected graph) G = (V, E)
含括樹(spanning tree) H= (V, T), T  E, 是
一個無向樹(undirected tree),它是G的子圖,
包含G的所有節點
最小含括樹MST是一個擁有最小(minimum)總
權重(weight)或總成本(cost)的含括樹。
26
最小含括樹範例


圖G的最小含括樹(非唯
一)
一個圖G
27
Kruskal最小含括樹演算法概念



Kruskal最小含括樹演算法是一個貪婪演算
法(greedy algorithm)
它採取貪婪解題策略產生給定圖G=(V, E)
的最小含括樹H=(V, T),每次都是挑選最
小成本且不形成cycle的邊加入目前的最小
含括樹的邊集合T之中
因為n個節點的樹具有n-1個邊,因此,經
過n-1次邊的挑選之後,就可以形成累積
成本最小的含括樹。
28
Kruskal最小含括樹演算法
Algorithm Kruskal最小含括樹演算法
Input: 無向加權圖G=(V, E),其中|V|=n
Output: G的最小含括樹(MST)H=(V, T)
1. T← //T為MST的邊集合,一開始設為空集合
2. while T包含少於n-1個邊 do
3.
選出邊(u, v),其中(u, v)E,且(u, v)的加權(weight)最小
4.
E←E-(u, v)
5.
if ( (u, v)加入T中形成循環(cycle) ) then 將(u, v)丟棄
6.
else T←T(u, v)
7. return H=(V, T)
29
Kruskal最小含括樹演算法執行範例
30
Kruskal最小含括樹演算法討論
Q: 我們如何檢查加入新的邊是否會形成循環?
A: 使用 集合 (SET) 尋找與 聯集 (UNION)操作



使用 集合 (SET) 與 聯集 (UNION)操作。
考慮樹的節點集合:
一開始產生n個包含單一節點的集合;也就是說若
V={v1,…,vn} ,則產生{v1}, {v2},…,{vn}
加入邊(u, v)是否會形成循環:
找出u,v所屬的集合,若 u, v 在相同的集合, 則加入邊(u, v)
會形成循環。反之,若uS1 , vS2 ,而且 S1S2則加入邊(u,
v)不會形成循環,此時應對 S1 與 S2 進行聯集操作。
31
Kruskal演算法的時間複雜度

時間複雜度: O(|E| log|E|)
排序
: O(|E| log|E|)
行2-6 迴圈 (幾乎每個邊都要檢查) O(|E|)
找出元素所在的集合 O(log |V|)
聯集兩集合 O(log |V|)


 : O(|E| log |V|)


O(|E| log|E|)
|E|  |V|2
=O(|V|2 log |V|)
=O(n2 log n)
32
3.5 Prim最小含括樹演算法
33
Prim最小含括樹演算法概念



Prim最小含括樹演算法是一個貪婪演算法(greedy
algorithm)。
它採取貪婪解題策略產生給定圖G=(V, E)的最小含
括樹H=(V, T)。此演算法先隨意挑一個節點加入集
合X中,此後每次都挑選一個一端的節點在X中,
而另一端的節點在(V-X)中的最小成本的邊。如此,
可保證將所挑選的邊加入T之後不會形成循環
(cycle),這代表H=(V, T)是一棵樹(tree)。
等挑完n-1個邊之後,H=(V, T) 就是最小含括樹
(MST)。
34
Prim最小含括樹演算法
Algorithm Prim最小含括樹演算法
Input: G=(V, E)為無向加權圖,其中|V|=n
Output:G的最小含括樹(MST)H=(V, T)
1. T← //T為MST的邊集合,一開始設為空集合
2. X←{v} //隨意選擇一個節點v加入集合X中
3. while T包含少於n-1個邊 do
4. 選出(u, v)E,其中uX且vV-X,且(u, v)的加權(weight)最小
5. T←T(u, v) //(u, v)是一個邊
6. X←X{v}
7. return H=(V, T)
35
Prim最小含括樹演算法執行範例
36
Prim最小含括樹演算法時間複雜度

總時間複雜度: O(n2),因為
外層的while迴圈(行3-6): n-1  O(n)
 內層迴圈(行4): 在(u, v)中選擇最小權
重,其中u屬於X,v屬於V-X  O(n)
(藉著使用Prim提出的兩個向量C1和C2)

(Ref: R. C. Prim, “Shortest connection networks and some
generalizations,” Bell System Technical Journal, 36(1389–1401), 1957.)

比較: 如果 |E|<<n2 ,則採用Kruskal演算法
(複雜度O(|E| log|E|)效能較佳
37
3.6
Dijkstra最短路徑演算法
38
圖的最短路徑


由圖(graph)中的某個節點(vertex or node)v到圖中的另一節
點u,若v到u之間存在一條路徑(path),則路徑中所經過的
邊(edge)的權值(weight)的總合稱為路徑的成本(cost)或距離
(distance)。所有路徑中具有最小成本的稱為最短路徑
(shortest path)。
由於最短路徑具有許多應用,因此有許多求取最短路徑的
演算法,著名的演算法包括:
(1) Dijkstra演算法(使用貪婪解題策略)
(2) Bellman-Ford演算法(使用動態規劃解題策略)
(3) Floyd-Warshall演算法(使用動態規劃解題策略)
39
Dijkstra最短路徑演算法設計者

E. W. Dijkstra(1930年5月11日-2002
年8月6日)生於荷蘭鹿特丹

在1972年獲得圖靈獎(Turing Award)

2002 年 , Dijkstra 獲 得 了 ACM PODC
(Principles of Distributed Computing)
最具影 響力 論文 獎(Influential Paper
Award) , 以 表 彰 他 在 分 散 式 計 算
(distributed computing)領域中關於自
我穩定(self stabilization)計算模式的
貢獻。為了紀念他,這個每年一度獎
項 也 在 此 後 被 更 名 為 Dijkstra 獎
(Dijkstra Prize)
Source: http://en.wikipedia.org/wiki/Edsger_W._Dijkstra
Creative Commons Attribution-Share Alike 3.0 Unported
Author:Hamilton Richards
40
Dijkstra最短路徑演算法
是喝咖啡時20分鐘想出的發明

“One morning I was shopping in
Amsterdam with my young
fiancée, and tired, we sat down
on the café terrace to drink a cup
of coffee and I was just thinking
about whether I could do this,
and I then designed the algorithm
for the shortest path. As I said, it
was a 20-minute invention. In
fact, it was published in 1959,
three years later.”
Thomas J. Misa (Editor), "An Interview with Edsger W.
Dijkstra," Communications of the ACM 53 (8): 41–47,
2010.
Attribution 2.0 Generic (CC BY 2.0)
Elliott Brown
Source: https://www.flickr.com/photos/ell-rbrown/14165662691/in/photolist-
41
Dijkstra最短路徑演算法介紹
Dijkstra演算法: Dijkstra演算法屬於求取單一(single)源
(source)節點至全部(all)終(destination)節點的單源點至全終
點之一至全(one-to-all)最短路徑演算法。
 Dijkstra演算法只能用在所有的邊都是非負邊(non-negative
weighted edge)的圖。因為負邊有可能產生負循環,因而無
法產生正確的最短路徑,而Dijkstra演算法並無法檢查給定
的圖是否有負循環。
 Dijkstra最短路徑演算法採用貪婪策略解決問題,每次都挑
選一個目前可以由源節點抵達距離(累積邊加權)最小的節點
往外調整其鄰居節點的最短路徑距離。在經過n次(n為節點
個數)的節點選擇之後,則所有的節點都可以求得由單一源
節點可以抵達的最短路徑距離。

42
Dijkstra最短路徑演算法
Algorithm Dijkstra最短路徑演算法
Input:給定一個非負加權有向圖(non-negative weighted digraph)G=(V, E),及一個
來源(source)節點s。G各邊的加權值以w[x][y]表示,其中x 及y為邊的二個節點。
Output:對每一個節點u而言,傳回一個由s到u的最短路徑距離(累積邊加權)d[u]。
1. d[s]←0; d[u]←∞ for each u≠s
2. 將每一個節點加入優先佇列Q
3. while Q≠ do
4.
自Q中移出具有最小d[u]值之節點u
5.
for 每一個與u相鄰之節點x do
6.
if d[x] > d[u]+w[u][x] then
7.
d[x]←d[u]+w[u][x]
8. return d
43
Dijkstra最短路徑演算法
如何記錄所有的路徑?



我們將d[u]以加中括號的方式標記在每一個節點旁,使用下圖
說明Dijkstra演算法求節點A到每一個節點最短路徑的過程。
若要讓Dijkstra演算法也能夠求出每一條最短路徑所經過的每
一個節點,則我們要將每一節點在最短路徑中的前一節點紀
錄下來,其作法為增加一個陣列p(代表predecessor,前行者)
來記錄最短路徑中的每一個節點的前一節點。並將Dijkstra演
算法之if敘述修改如下:
if (d[x] > d[u]+w[u][x]) then
d[x]←d[u]+w[u][x]
p[x]←u //此敘述為新加入者,代表在最短路徑中節點x的前一節點為u
44
Dijkstra演算法執行範例
45
Dijkstra最短路徑演算法複雜度
假設G一共有n個節點,m個邊(也就是|V|=n, |E|=m)
 行2將每一個節點加入優先佇列Q,因此Q具有n個元素
 行3的while迴圈每次迭代會自Q中次移出一個節點,因此會
執行n次迭代
 行4使用O(log n)時間自Q中移出最小d[u]值之節點u
 行5的for迴圈在整個演算法的執行過程中一共執行m次迭代
 行7使用O(log n)的時間根據新的d[u]值更新u在Q中的位置(
先刪除u在新增u
因此總時間複雜度為O((n+m) log n)=O( (|V|+|E|) log |V|)
46
3.7
動態規劃演算法基本概念
47
動態規劃解題策略


動態規劃演算法(dynamic programming algorithm)使用動態
規劃策略(dynamic programming strategy)解決問題。它將
原問題分解成一系列子問題(subproblems),並依序解決子
問題來解決原問題。為避免一再地解重複的子問 題,一旦解
出子問題的解答(solution),即會將其存在表格(或陣列)中。
當需要用到某一子問題的解答時,即直接從表格中取出其解
答以節省計算時間,是一個「系統化」的、「節省不必要計
算」的、「以空間換取時間」的演算法。
一個動態規劃演算法一般先解出最簡單的子問題,並以一定
的程序持續運行直至求出原問題解答為止。
48
最佳解原則
最佳解原則(Principle of Optimality):


假設我們可以將一個問題P分解為一系列的子問題
P1 , P2, …, Pn-1, Pn,而必須作出一系列的決策 D1,
D2, …, Dn-1, Dn
若這一系列的決策 D1, D2, …, Dn-1, Dn可以產生P的
最佳解,則針對於完成第i個到第j個(1ijn)連續決
策後所產生的新狀態而言(也就是在新狀態解決子問
題P1,…,Pi-1,Pj+1,…,Pn) ,其他的決策相依於這個狀態
必定也能產生最佳解。
49
動態規劃與貪婪演算法之比較
比較:
二者都是透過一系列的決策以解決問題,但是有
以下的不同點:



在貪婪演算法中,任何決策都是獨立
(independent)的,都只要考慮區域最佳解(locally
optimal)。這些區域最佳解最後會加成為全域最佳
解(globally optimal solution)。
在動態規劃演算法中,決策是相依的
(dependent)。相依於第i個到第j個(1ijn)決策所
產生的狀態(子問題)而言,其他的決策必定也是最
佳的,藉以求得全域最佳解(globally optimal 50
使用動態規劃解題策略的演算法





Bellman-Ford最短路徑演算法
Floyd-Warshall最短路徑演算法
多階圖最小成本路徑演算法
最長共同子序列演算法
矩陣鏈乘積演算法
51
3.8
Bellman-Ford
最短路徑演算法
52
Bellman-Ford最短路徑演算法
介紹
與Dijkstra演算法相同,Bellman-Ford演算
法也是屬於求取單一源節點至全部終節點
的一至全最短路徑演算法。
但是與Dijkstra演算法不同的是,BellmanFord演算法可以檢查圖是否有負加權循環
(cycle) , 因 此 在 具 有 負 加 權 (negative
weight)邊的圖也可以正確的執行。

53
Bellman-Ford最短路徑演算法
介紹(續)

Bellman-Ford最短路徑演算法採用動態規劃策略解
決問題。一開始在第1次迭代先求出所有屬於1-邊
路徑(1-edge path)的最短路徑,並將其最短路徑距
離儲存在陣列中;然後基於這個儲存結果在第2次
迭代針對每個邊,由始點(starting node)往外調整到
止點(ending node)的最短路徑距離,可以得出所有
屬於2-邊路徑(2-edge path)的最短路徑;…。依此
類推則在第n-1次迭代可以求出所有屬於(n-1)-邊路
徑((n-1)-edge path)的最短路徑。因為具n個節點的
圖最長的路徑具有n-1個邊,因此第n-1次迭代求出
的路徑已經是最終的正確結果了。
54
Bellman-Ford最短路徑演算法
Algorithm Bellman-Ford最短路徑演算法
Input: 給定一個加權有向圖(weighted digraph)G=(V, E),及一個來源(source)節點s。G各
邊的加權值以w[x][y]表示,其中x 及y為邊的二個節點。
Output: 對每一個頂點u而言,傳回一個由s到u的最短路徑距離(累積邊加權)d[u]。
1. d[s]←0; d[u]←∞ for each u≠s
2. for i←1 to |V|-1 do
3. for 每一個G的邊(u, x) do
4.
if d[x] > d[u] + w[u][x] then
5.
d[x]← d[x] + w[u][x]
6. for 每一個G的邊(u, x) do //檢查有無負循環(negative-weight cycle)
7.
if d[x] > d[u] + w[u][x] then return false //代表有負循環,無法產生正確結果
8. return d
55
Bellman-Ford最短路徑演算法
複雜度
假設G一共有n個節點,m個邊(也就是|V|=n, |E|=m)
 行2-5的外層for迴圈一共有n-1次迭代
 行3-5的內層for迴圈一共有m次迭代
 行4-5為內層if指令,針對每個邊(u, x)依據目前的d[u]值調
整d[x]
 行6-7的for迴圈在求出(n-1)邊路徑之後再針對每個邊(u, x)
依據目前的d[u]值調整d[x],若有任何調整產生則表示有一
個n邊路徑(也就是循環)
因此總時間複雜度為行2-5的外層for迴圈n-1次迭代次數與
行3-5的內層for迴圈m次迭代相乘得O(n  m)= O(|V|  |E|)
56
Bellman-Ford最短路徑演算法
執行範例
57
3.9
Floyd-Warshall
最短路徑演算法
58
Floyd-Warshall最短路徑演算法
介紹

與Dijkstra演算法與Bellman-Ford演算法不同的是,
Floyd-Warshall演算法可以求出全部節點配對的最
短路徑,是一個全配對最短路徑(all-pair shortest
path)演算法。

Floyd-Warshall演算法可以處理有負邊的圖,但是
不能用以檢查有負迴圈的圖。
59
Floyd-Warshall最短路徑演算法
介紹(續)



Floyd-Warshall演算法採用動態規劃策略解決問題,利
用一個n×n(n為節點總數)的二維陣列d來記錄每一節點
配對間的最短路徑成本或距離(distance) 。
在啟始(initial)狀況時, d[i][j]=w[i][j],for each i and j。
(w[i][j]=0,for i=j; w[i][j]=, for (i, j); w[i][j]=the
weight of (i, j) for (i, j) E)
Floyd-Warshall演算法執行時會不斷的更新陣列d。在第
k次更新陣列d時,表示d中所紀錄的最短路徑是經由編
號小於或等於k的節點當作中間節點所造成的。因此,
當第n次更新陣列d時,則表示d中所紀錄的最短路徑是
可以經由所有節點當作中間節點所造成的,這也就是
演算法所需要的結果。
60
Floyd-Warshall最短路徑演算法
Algorithm Floyd-Warshall最短路徑演算法
Input:G為一個加權圖有向(weighted digraph), G中各邊的加權值以w[x][y]表示
,x 及y為邊的二個頂點。
Output:G中的每一個節點配對的最短路徑距離d[x][y],及對應的路徑前節點
p[x][y],其中x及y為邊的二個節點
1. d[i][j]=w[i][j],for each i and j
2. for(k←1 to n) do //假設節點的編號由1至n
3. for(i←1 to n) do
4.
for(j←1 to n) do
5.
if (d[i][j]>d[i][k]+d[k][j])
6.
d[i][j]←d[i][k]+d[k][j]
7.
p[i][j]←p[k][j]
8. return d
61
Floyd-Warshall演算法討論

可以使用一個前節點陣列(predecessor
matrix)p紀錄每個節點在最短路徑上的前
節點。初始化p[i,j]時,若i=j或(i,j)∉E則初
始為NIL(),否則初始為i。

等執行完演算法後,則可藉由前節點陣列
來建立出由任意節點到其他任意節點的最
短路徑。
62
Floyd-Warshall最短路徑演算法
範例: 陣列初始化
G(V, E)
s
a
b
c
d
s
0




a
6
0

2
1
b

2
0
3
6
c
3
4

0

d


1
5
0
d[i][j]
s
a
b
c
d
s





a
s


c
d
b

a

c
d
c
s
a



d


B
c

p[i][j]
63
Floyd-Warshall最短路徑演算法
複雜度
假設G一共有n個節點(也就是|V|=n)
 行2的外層for迴圈一共有n次迭代
 行3的中層for迴圈一共有n次迭代
 行4的內層for迴圈一共有n次迭代
 行5-7的if敘述的執行為常數時間
因此總時間複雜度為O(n3)=O(|V|3)
64
3.10
多階圖最小成本路徑演算法
65
多階圖最小成本路徑問題
(multi-stage graph minimum-cost path problem)





多階圖G=(V,E) 是有向圖(directed graph),其節點
被分割成 k2 個互斥集(disjoint sets) Vi, 1 i  k。
此外,若<u,v>是E的邊,則uVi 且 vVi+i, 1 i
<k,每個邊都有一個加權(weight)wi,i+1 (或稱為成
本或距離)。
其中集合 V1 和 Vk 都僅包含一節點(node or vertex)。
多階圖問題是要找出從 V1 中的源點(source)s 到 Vk
中的標點(target) t 的最小成本路徑(minimum-cost
path)。
每一個集合 Vi 被定義為圖中的階(stage)。
66
貪婪演算法無法解決
多階圖最小成本路徑問題




例:從多階圖(multi-stage graph)中找出v0到v3的最短路徑。
貪婪演算法: v0v1,2v2,1v3 = 23
最佳解: v0v1,1v2,2v3 = 7
貪婪演算法無法解決此問題,這是因為不同階(stage)的決
策會影響到其他階的決策。
67
貪婪演算法無法解決
多階圖最小成本路徑問題(續)

4
A
例如:
D
1
11
S
2
5
B
18
9
E
16
13
T
2
5
C



2
F
貪婪演算法無法解決此問題: S A D T 1+4+18 = 23.
最短路徑為: S C F T 5+2+2 = 9.
就像分期買商品一樣,都分三期付款,最終都可以得到商品的
產權。有的付款方式第一期要繳1萬,有的要繳2萬,有的要繳5
萬。但是依照不同的第一期繳法,則在第二期甚或第三期都有
不同的繳款選擇,而造成繳款總額的不同。
68
動態規劃

動態規劃方法:
1
S
2
B
5

A
C
d(A, T)
d(B, T)
T
d(C, T)
d(S, T) = min{1+d(A, T), 2+d(B, T),
5+d(C, T)}
69
動態規劃
4
A
D
1
A
4
11

11
D
E
d(D, T)
S
T
d(E, T)
2
5
B
18
9
E
16
13
T
2
5
C
2
F
d(A, T) = min{4+d(D, T), 11+d(E, T)}
= min{4+18, 11+13} = 22.
70
動態規劃
d(B, T) = min{9+d(D, T), 5+d(E, T), 16+d(F, T)}
= min{9+18, 5+13, 16+2} = 18.
d(C, T) = min{ 2+d(F, T) } = 2+2 = 4
d(S, T) = min{1+d(A, T), 2+d(B, T), 5+d(C, T)}
= min{1+22, 2+18, 5+4} = 9.



4
A
D
1
11
S
2
9
5
B
E
16
13
T
B
5
D
E
d(D, T )
d(E, T )
T
2
5
C
9
18
2
F
16
F
d(F, T )
71
解決多階圖最小成本路徑問題的
動態規劃演算法
Algorithm 多階圖最小成本路徑演算法
Input:具n個頂點(vertices)的k階多階圖G(V, E), V= i=1..k Vi , ViVj= for ij,
V1={1},Vk={n}, <x,y>E (xVi  yVi+i), <x,y>的權重為w[x,y]
Output: 具k個節點由節點1到節點n的最小成本路徑p[1..k],成本為d[1]
1. d[n]=0; d[1..n-1]=; //陣列d儲存節點到標點t的最小距離(distance)
2. for jk-1 to 1 do
3.
for every node x in Vj do
4.
for every edge <x, y>E do
5.
if (d[x]>w[x,y]+d[y]) do
6.
d[x]=w[x,y]+d[y]
7.
s[x]=y //s代表節點的下節點(successor)
8. p[1]=1;p[k]=n;
9. for j2 to k-1 do p[j]s[p[j-1]];
10. return p,d[1]
72
3.11
最長共同子序列演算法
73
最長共同子序列





以下我們說明最長共同子序列(Longest common
subsequence, LCS or LCSS)相關背景知識
令X為一個由若干符號依序排列組成的序列(sequence),則X
的子序列(subsequence)為從X刪除0個或多個符號(不必要為
連續性的)的序列
例: 令X = b a c a d,則ad, ac, bac, acad, bacad, bcd等與
空序列都是A的子序列
例: 序列X = b a c a d 與 Y = a c c b a d c b 的共同子序列
(common subsequence)有: ad, ac, bac, acad等
例: 序列X與Y的最長共同子序列(longest common
subsequence)為: a c a d
74
最長共同子序列應用:
DNA序列比對
DNA = {A|C|G|T}*
(A: 腺嘌呤; C: 胞嘧啶; G: 鳥嘌呤; T: 胸腺嘧啶)
S1=ACCGGTCGAGTGCGGCCGAAGCCGGCCGAA
S2=GTCGTTCGGAATGCCGTTGCTGTAAA
Q: S1與S2是否為相似的DNA序列?
A: 這問題可以由找出S1與S2的最長共同子序列
來解決。
75
最長共同子序列應用:
化身路徑群組
化身路徑群組(Avatar Path Clustering):

由於相似的個性,興趣或習慣,網路虛擬環境(Networked Virtual Environment, NVE)或巨量多
人線上遊戲(Massively Multiplayer Online Game, MMOG)的用戶或化身(avatar)可能具有相似的
行為模式,導致在虛擬世界中有著類似的化身路徑。

我們希望將類似的化身歸類為一個群組,並為他們找到代表性路徑(representative path, RP)。


參考論文: Jehn-Ruey Jiang, Ching-Chuan Huang, and Chung-Hsien Tsai, “Avatar Path Clustering in Networked Virtual Environments," in Proc. of the 4th International
Workshop on Peer-to-Peer Networked Virtual Environments (P2PNVE 2010), 2010.
下圖來源: Huiguang Liang, Ransi Nilaksha Silva, Wei Tsang Ooi, Mehul Motani, “Avatar mobility in user-created networked virtual worlds: measurements, analysis, and
implications,” Multimedia Tools and Applications, v.45 n.1-3, p.163-190, October 2009.
76
最長共同子序列應用:
化身路徑群組(續)

在第二人生(Second Life, SL)贈品島(Freebies
Island)的兩條路徑有多相似?
77
最長共同子序列應用:
化身路徑群組(續)
將化身路徑轉為序列:
將虛擬世界切割為方格
(grid cell),並針對化身
路徑每隔固定時間取樣,
找出其所在方格編號形成
序列。
SeqA:C60.C61.C62.C63.C55.C47.C39.C31.C32
78
最長共同子序列應用:
化身路徑群組(續)
SeqA :C60.C61.C62.C63.C55.C47.C39.C31.C32
SeqB :C60.C61.C62.C54.C62.C63.C64
LCSSAB :C60.C61.C62. C63
找出兩條路徑對應的
最長共同子序列以衡
量其相似程度。
79
最長共同子序列問題
以下我們定義最長共同子序列(Longest
Common Subsequence, LCS)問題:
 給定兩個序列X = <x1,x2,...,xm>, Y =
<y1,y2,...,yn>,找出X和Y的最長共同子序列長
度
80
最長共同子序列問題
暴力法時間複雜度
產生序列X(或Y)的所有子序列,然後檢查每
個子序列是否也是序列Y(或X)的子序列,然
後儲存下最長的子序列並輸出。複雜度為:
 n * 2m = O(2m)
或
 m * 2n = O(2n )
Q1: 如何產生一個序列的所有子序列?
Q2: 如何檢查一個序列是否為另一個序列的
81
子序列?
最長共同子序列問題
子問題的遞迴關係
我們定義Xi = < x1,x2,...,xi >及Yj = <y1,y2,...,yj>。
令c [i, j]是Xi 和Yj 的LCS的長度,則我們有以下
遞迴關係:
if i=0 or j=0

0

if i,j>0 and xi=y
c[i, j]  
c[i -1, j -1] +1
max{c[i, j -1], c[i -1, j]} if i,j>0 and x  y
j

i
82
j
最長共同子序列演算法
Algorithm 最長共同子序列演算法
Input: 兩個序列X = <x1,x2,...,xm>, Y = <y1,y2,...,yn>
Input: X和Y的最長共同子序列長度
1 m  length[X]
2 n  length[Y]
3 for i  1 to m do
4
c[i, 0]  0
5 for j  1 to n do
6
c[0, j]  0
83
7 for i  1 to m do
8
for j  1 to n do
9
if xi = yj then
10
c[i, j]  c[i-1, j-1]+1
11
b[i, j]  0 “” //for both i-1 and j-1
12
else if c[i–1, j]  c[i, j-1] then
13
c[i, j]  c[i-1, j]
14
b[i, j]  “” //for i-1
15
else c[i, j]  c[i, j-1]
16
b[i, j]  “” //for j-1 only
17 return c and b
84
最長共同子序列演算法
執行範例
X=ABCBDAB
Y=BDCABA
85
最長共同子序列演算法
時間複雜度
 行7的外層for迴圈一共有m次迭代
 行8的內層for迴圈一共有n次迭代
 行9-16的if敘述需要常數時間
因此總時間複雜度為O(mn) ,而非暴力法的 O(2m)
或 O(2n)
86
最長共同子序列演算法
如何找出最長共同子序列
PRINT_LCS(b, X, i, j )
1 if i = 0 or j = 0 then
時間複雜度: O(m+n)
2 return
3 if b[i, j] = “” then
4 PRINT_LCS(b, X, i-1, j-1)
5 print xi
6 else if b[i, j] = “” then
7 PRINT_LCS(b, X, i-1, j)
8 else PRINT_LCS(b, X, i, j-1)
藉由呼叫PRINT_LCS(b, X, length[X], length[Y])函數來印出 LCS
87
3.12
矩陣鏈乘積演算法
88
矩陣鏈乘積
(matrix-chain product)



Q: 如何以最少的純量(scalar)乘法,算出
A1…An的矩陣鏈乘積?
A: 加上括號指定計算矩陣乘積最佳順序
舉例: A1 A2 A3 A4
( A1( A2 ( A3 A4 ))) ( A1(( A2 A3 ) A4 ))
(( A1 A2 )( A3 A4 )) (( A1( A2 A3 )) A4 )
((( A1 A2 ) A3 ) A4 )
89
二個矩陣相乘的演算法
MATRIX MULTIPLY(A,B)
1 if columns[A]  rows[B]
2
then error “不相容的矩陣大小”
3
else for i 1 to rows[A]
4
for j 1 to columns[B]
C[i, j ]  0
5
6
for k 1 to columns[A]
C[i, j ]  C[i, j ] + A[i, k ]B[k , j ]
7
8 return C
90
二個矩陣相乘時間複雜度:

假設 A 是一個 p  q 的矩陣,B 是一個
q  r 的矩陣, 那個 A x B
的時間複雜
度為 p  q  r 。
91
矩陣相乘執行順序非常關鍵
假設 A1 是個10  100 的矩陣, A2 是一個100  5
的矩陣, A3 是一個 5  50 的矩陣。
 那麼算出 (( A1 A2 ) A3 ) 需要
10  100  5 + 10  5  50  7500 次的純量相乘。
 然而算出 ( A1( A2 A3 )) 卻需要
100  5  50 + 10  100  50  75000 次的純量相乘。

92
矩陣鏈乘積問題
(matrix-chain product problem)


給定一長度為n的矩陣鏈  A1 , A2 ,..., An ,
對於i=1,2,…,n而言,矩陣Ai 的維度為
pi-1pi。找出一種方式對 A1 A2 ... An 進行
完全括號(fully parenthesized)以最少的
純量乘法求出矩陣鏈乘積。
若一個矩陣鏈乘積為完全括號,則其包
含單一矩陣或為兩個完全括號矩陣鏈乘
積的相乘。
93
矩陣鏈乘積問題
窮舉所有不同的括號方式:

不同括號方式總數相當於將矩陣鏈在第k個矩陣之
後與第k+1個矩陣之前,使用括號分為二組後再計
算其結果,而1kn-1。我們可得:
1
if n  1


P(n)   n -1
P(k)p(n - k) if n  2

 k 1

實際上,P(n)為卡塔蘭數(Catalan number)=Cn-1
=O(2n)
94
卡塔蘭數(Catalan number)


卡塔蘭數是以比利時的數學家歐仁查理
卡塔蘭(Eugène Charles Catalan, 1814–
1894)命名。
卡塔蘭數的一般項公式為
n
2
n


1
4
Cn  n + 1  n   ( n3/ 2 )
95
矩陣鏈乘積演算法解題思維
步驟1:找出子問題切割方式
Optimal
(( A1 A2 ... Ak )( Ak +1 Ak + 2 ... An ))
Combine
96
矩陣鏈乘積演算法解題思維步
驟 2: 找出子問題遞迴關係


定義 m[i, j]= 計算 Ai.. j  Ai Ai+1.. A j 所需的
最小相乘數。
目標為求得 m[1, n]

0
i j

m[i, j]  
min i k  j{m[i, k] + m[k + 1, j] + p i -1p k p j} i  j
97
矩陣鏈乘積演算法解題思維步
驟 3: 以表格儲存計算過的資訊


與其一再地遇到相同問題而重複遞迴求
解,取而代之地我們利用一表格化的
(tabular)、由下而上(bottom-up)的方式
來計算最低成本。
過程利用一輔助表格m[1..n, 1..n] 來紀
錄最小成本m[i, j] ,並利用另一個輔助
表格s[1..n, 1..n]來記錄哪一個指標 k 造
就了m[i, j]的最小成本。
98
矩陣鏈乘積演算法
MATRIX_CHAIN_ORDER
MATRIX_CHAIN_ORDER(p)
1 n  length[p] –1
2 for i  1 to n
3
do m[i, i]  0
4 for l  2 to n
5
do for i  1 to n – l + 1
6
do j  i + l – 1
7
m[i, j]  
8
for k  i to j – 1
9
do q  m[i, k] + m[k+1, j]+ pi-1pkpj
10
if q < m[i, j]
11
then m[i, j]  q
12
s[i, j]  k
13 return m and s
時間複雜度:
3
O( n )
99
例子:
A1
A2
30  35  p0  p1
35  15  p1  p2
A3 15  5
A4 5  10
A5 10  20
A6 20  25




p2  p3
p3  p4
p4  p5
p5  p6
100
在n=6時, MATRIX-CHAIN-ORDER所計算出的
m 與 s 表格
101
m[2,5]=
min{
m[2,2]+m[3,5]+p1p2p5=0+2500+351520=13000,
m[2,3]+m[4,5]+p1p3p5=2625+1000+35520=7125,
m[2,4]+m[5,5]+p1p4p5=4375+0+351020=11374
}
=7125
102
印出最佳括號方式
PRINT_OPTIMAL_PARENS(s, i, j)
1 if i=j
2 then print “A”i
3 else print “(“
4
PRINT_OPTIMAL_PARENS(s, i, s[i,j])
5
PRINT_OPTIMAL_PARENS(s, s[i,j]+1, j)
6
print “)”
 例: (( A1( A2 A3 ))(( A4 A5 ) A6 ))
103
The End
104
Download