--- tags: Note --- # 演算法 ## 1. 緒論 ### 定義: 針對一個問題,給予有限個明確的步驟,在有限時間內解出問題的方法 + 每個步驟都要清晰明確 + 輸入值域要清楚 + 一種演算法可以用不同形式描述 + 可能存在一種以上解決相同問題的演算法 + 不同演算法對同一個問題有不同思路,花的時間也不一樣 + 在有限時間內得到輸出 ### 解決問題的程序: 理解問題 => 了解電腦設備的性能 => 決定精確解法或近似解法 => 確定適當的資料結構 => 設計演算法 => 詳細表述演算法 => 證明演算法正確性 => 分析演算法 => coding ### 重要的問題: + 排序 + 搜尋 + 字串處理 + 圖問題 + 組合問題 + 幾何問題 + 數值問題 ### 基本資料結構 #### 線性資料結構 + **array (有index)** ![array](https://ds055uzetaobb.cloudfront.net/image_optimizer/7bfe2713ecaf427164d14018608b826ffbeea531.jpg) + **linked-list (沒有index)** ![linked-list](https://blog.kdchang.cc/2016/09/21/javascript-data-structure-algorithm-linked-list/linked-list-types.png) + **stack (後進先出)** ![stack](https://www.tutorialspoint.com/data_structures_algorithms/images/stack_representation.jpg) + **queue (先進先出)** + ![queue](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Queue_Algorithm.svg/2000px-Queue_Algorithm.svg.png) #### 圖 + 有向圖 + 無向圖 + 有根樹 + 有序樹 + 二元樹 #### 集合與字典 ## 2. 演算法效率分析 $O()$ big-o (最大演算時間) $O(n^2)$ 是 order of growth 小於 $n^2$ $\Omega()$ omega(最小演算時間) $\Omega(n^2)$ 是 order of growth 大於 $n^2$ $\Theta()$ theta (平均演算時間) $\Theta(n)$ 是 order of growth 等於 $n$ ### 常見的 order of growth 類型: 1 常數 $log(n)$ 對數(sublinear) $n$ 線性 $nlog(n)$ $n^2$ 平方 $2^n$ 指數 ### 例子 #### binary search: $O(log_2n)$ 最壞的狀況,假設有n個項,需要切x次 $\frac{1}{2}^x = n$,求x #### bellman-ford algorithm (最短路徑) 假設有$m$個edge, $n$個node: 對edge做iteration 最壞為每次只更新一個node的權重 $\implies m\times n$ #### 行列式降階: 每次少一階:$\frac{n(n+1)}{2}$ => $O(n^2)$ ## 3. 圖 Graph - n 個 nodes (vertices) - m 個 edges ($m \leq n^2$) ### 表示方式 #### adjacency list - 空間 $O(n+m)$ (= input size) - BFS, DFS 遇到用 adjacency list 表示的表示的 graph 時只需要 $O(n+m)$ 的時間複雜度 #### adjacency matrix - 空間 $\Theta(n^2)$ ### 無向圖 undirected graph - connected: 是否 graph 內部任兩個 node 之間都有 path #### Connected Component: - 任兩個 node 之間都有 path 的最大集合 - 彼此之間沒有交集 ### 有向圖 directed graph - s-t 有 path != t-s 有 path - Strongly connected: 是否 graph 內部任兩個 node 之間都有**雙向** path #### Strongly Commected Component: - 任兩個 node 之間都有**雙向** path 的最大集合 - 彼此之間沒有交集 ### 廣度優先搜尋 BFS - discover array: 當 BFS 找到一個 node $n$,discover($n$) = True - Quene: first-in, first-out - Layers: 初始 L(0) 只有起點 s,找到 node 就加入下一層 #### 實作 iterates over nodes in each layers,在 L(i) 內的 node $u$,找到 node $v$,檢查 discover($v$) 是否為 False,是的話: - v 加入 L(i+1) - (u, v) 加入 BFS Tree #### BFS Tree - BFS 找到的 nodes 和 經過的 edges - BFS Tree 內的所有 nodes 一定是 connected component ### 深度優先搜尋 DFS - explored array: 當對一個 node $n$ 做 DFS 時,explored($n$) = True - Stack: last-in, first-out - 和 BFS 不同: discover 時不做標記 #### 實作 - 用一個 Stack $S$ 搜集每次看到的 nodes - iterate over $u \in S$,標記 explored,把所有和 $u$ 鄰接的 node 加入 $S$ - 直到 $S$ 空了 ### 二分圖 Bipartite Graph - 定義:所有 nodes 可以分為兩個子集使得所有 edges 兩端連接於不同子集 - 性質: - 沒有 odd cycle (奇數 nodes 的圈) #### Testing Bipartiteness of a Graph - BFS - 奇偶 Layer 標上不同顏色 - iterate over edges,檢查顏色是否都不同 ### Directed Acyclic Graphs (DAGs) - 沒有 cycle 的有向圖 - 有 topological ordering: 存在一種 nodes 排序使所有 edges 指向單一方向 - 優先權應用 #### 判斷是否為 DAG - DFS,如果某次加入的 edge 的端點已經在 discover 內 $\implies$ 有環 #### 找一個 DAG 的 topological ordering - set $S$:包含所有無 incoming edge 的 nodes - $n = S.\text{pop}()$,把 $n$ 移除 - 檢查 $n$ 的 outcoming edges 鄰接 nodes 是否已無 incoming edge: - 是:加入 $S$ ## 4. 貪心法 Greedy algorithm 每一步都是最佳解,不能回溯修改 ### 排程問題 Interval Scheduling Problem - 同樣時間內排出最多行程 - 行不通的 Greedy rule:最早開始,最短結束,最少衝突 - 可行的:最早結束 #### 實作 $O(n\log{n})$ - 排序 ending time: $O(n\log{n})$ - 排程 $O(n)$ #### proof 和某個已知 optimal 比較,上述實作的第 i 個行程的結束時間一定比 optimal 的第 i 個還早 ### 區間著色 Interval Partitioning (Coloring) 最少要幾個 Core 才能完成這些 Request - 應用:伺服器問最少需要買的流量 #### 深度 $O(n\log{n})$ - 排序時間陣列 $s_1, s_2, s_3, f_2, f_1, s_4 .....$ - 深度: s:+1, f:-1 => 最大深度 $d$(最糟所需要的 core 數) #### 實作:塗色 labels: $1, 2, ..., d$ - 以開始時間順序:抓 labels - 結束:吐出 labels #### proof 1. 不會 overlap 2. 每個 request 都會被排到 ### 最小延遲 Scheduling to Minimize Lateness - 交作業問題 - 每個作業都有 deadline - Lateness: $\max(0, f(i) - d_i)$ - No idle time (休息) #### Greedy Rule - 行不通的:最短時間先做,Slack = $d_i - t_i$ 最小先做 - deadline 早的先做 #### Exchange argument - 抽換最佳解,最佳解仍是最佳解 - inversion: deadline 早的後做 - deadline 很晚的情況下,先做哪個沒差,所以可以有多種最佳解 ### 最短路徑 Shortest path - Dijkstra 算法 (j不發音) - weights > 0 - 可以找出整張圖的 s 到任意一點 v 最短路徑 #### 實作 - set S = $\{\phi\}$ - $d_v$: 最短距離陣列 - 起點 s 加入 S - 對每個圖裡且鄰接 S 的 node,找 S 到 node 的最短距離並儲存 ### Huffman codes - 最佳的 prefix codes(字根不重複) - 每次合併頻率最小的字 - 左0右1 - $O(n\lg{n})$ - 可以用 BFS 以 $O(n+m) = O(2n-1) = O(n)$ 找出編碼 ### kruskal's algorithm + 如果自kruskal及prim 中,把邊的權值調成負數,仍能正常運作嗎? ANS: 可以,因為負值可以視為正值的平移,做完kruskal 之後再平移回來就好。 + kruskal 做最小生成森林: 把圖分割,對每個分割做kruskal ### steiner problem 最短路徑和問題,可以加入平面上不存在的點 (steiner points) 每個 steiner point 的 degree 必須是 3 $\implies$ 120 度 ![三點最佳解](https://upload.wikimedia.org/wikipedia/commons/thumb/3/3f/Steiner_3_points.svg/330px-Steiner_3_points.svg.png =250x)![四點最佳解](https://upload.wikimedia.org/wikipedia/commons/thumb/e/e4/Steiner_4_points.svg/330px-Steiner_4_points.svg.png =250x) ### 渡河問題 a[0]+a[1]*2+a[n] a[0]*2+a[n-1]+a[n] 每次選兩者比較取小的那個 ## 費波那契 秤重問題 + 砝碼只能放天平一邊: 2進位 + 可以放兩邊: 3進位 # Divide and Conquer ## 主定理 master theorm - $T(n) = aT(\frac{n}{b}) + f(n)$ - 判斷 $f(n)$ 是否增長比 $n^{\text{log}_ba}$ 快 - 慢:$\Theta(n^{\text{log}_ba})$ - 相等:$\Theta(n^{\text{log}_ba}\log{n})$ - 快:$\Theta(f(n))$ ## Tromino puzzle - [play this](https://www3.amherst.edu/~nstarr/trom/puzzle-8by8/) - 用小 L 拼出大 L # Dynamic Programming ## world cup series - A, B 兩隊一直比賽,A勝率p,當A剩下i場要贏,B剩下j場要贏時,A的勝率為 P(i,j) - P(i,j) = (1-p)P(i,j-1) + pP(i-1,j) ```graphviz digraph hierachy { "P(i, j)"->"P(i-1, j)" [label=p] "P(i, j)"->"P(i, j-1)" [label="1-p"] } ``` ## Warshall 演算法 - 遞移封閉集 transitive closure - 十字檢查:a$\to$b 和 b$\to$c 有路徑$\implies$a$\to$c 有路徑$\implies$改成$1$ ```graphviz digraph { c b -> d d -> c [constraint=false] d -> a [constraint=false] {rank = same; a -> b;} {rank = same; c; d;} } ``` **(1)鄰接矩陣** $$\begin{matrix} & a & b & c & d \\ a & 0 & 1 & 0 & 0 \\ b & 0 & 0 & 0 & 1 \\ c & 0 & 0 & 0 & 0 \\ d & 1 & 0 & 1 & 0 \end{matrix} \tag{1}$$ **(2)遞移封閉集** $$\begin{matrix} & a & b & c & d \\ a & 1 & 1 & 1 & 1 \\ b & 1 & 1 & 1 & 1 \\ c & 0 & 0 & 0 & 0 \\ d & 1 & 1 & 1 & 1 \end{matrix} \tag{2}$$ ## Floyd 演算法 ```graphviz digraph { a ->b [style=invis] {rank = same; b -> a [label=2];} {rank = same; c -> d [label=1];} a -> c[label=3] d -> a[label=6] c -> b[label=7] } ``` **(1) 加權矩陣** $$\begin{matrix} & a & b & c & d \\ a & 0 & \infty & 3 & \infty \\ b & 2 & 0 & \infty & \infty \\ c & \infty & 7 & 0 & 1 \\ d & 6 & \infty & \infty & 0 \end{matrix} \tag{2}$$ **(2) 距離矩陣** $$\begin{matrix} & a & b & c & d \\ a & 0 & 10 & 3 & 4 \\ b & 2 & 0 & 5 & 6 \\ c & 7 & 7 & 0 & 1 \\ d & 6 & 16 & 9 & 0 \end{matrix} \tag{1}$$ - 完全最短路徑問題 ## P,NP, NP-complete ![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/P_np_np-complete_np-hard.svg/800px-P_np_np-complete_np-hard.svg.png) + P問題(polynomial) 可以在多項式時間複雜度 $O(n^k)$ 內求解的問題 + NP問題(non-deterministic polynomial) 可以在多項式時間複雜度內驗證答案是否正確的問題 + NP-hard 只要有一個NP困難問題找到P解,那麼所有NP問題都是P問題 ### NP-Complete - 條件1: 本身為NP - 條件2: 所有 NP 問題都可以 reduce 成 NP-Complete - A 可以被 reduce 成 B: $A \leq_p B$ 代表可以用B的解法來解A(但是不一定可以用A的解法來解B),所以B至少跟A一樣難 - NP-Complete 問題至少跟 NP 問題一樣難 - NP-Complete 的解法可以用來解所有 NP 問題 - 如果證明 NP-Complete 問題有 P 時間解,即 P = NP