考研相關文章參考資料為 wjungle 大神提供的筆記

Graph

  • 令 G=<V,E>G = <V, E> 代表圖形是由兩個非空集合組成:
    • VV: 代表頂點 (Vertex)
    • EE: 代表邊 (Edge)
  • 根據邊的類型,可分為兩類:
    • Undirected Graph (無向圖)
      • 邊不具有方向性
      • (i,j)=(j,i)(i,j) = (j,i) 代表同一邊
    • Directed Graph (有向圖)
      • 邊具有方向性
      • (i,j)≠(j,i)(i,j) \neq (j,i)

相關術語

  • Eulerian cycle (尤拉 cycle)
    • 從某點出發,經過每個邊各一次,又回到原點
    • 充分必要條件: 每個頂點之 degree 為偶數
  • Eulerian chain
    • 從某點出發,經過每個邊各一次,不一定要回到原點
    • 充分必要條件: 有兩個頂點之 degree 為奇數,剩餘頂點之 degree 為偶數
  • Hamiltonian Path (漢米爾頓路徑)
    • 從某點出發,經過每個頂點各一次,不一定要回到原點
    • Hamiltonian cycle: 要回到原點

  • Complete Graph (完全圖)
    • 具有最多邊數的圖
    • nn 個頂點的無向圖: n(n−1)2\frac{n(n-1)}{2} 條邊
    • nn 個頂點的有向圖: n(n−1)n(n-1) 條邊
  • Subgraph & Component (子圖)
  • Path
  • Path length
    • 路徑上的邊數
  • Single Path
    • 除了起點與終點可能相同之外,中間經過的頂點皆不相同
    • ex:
      • 1-2-3-4 (O)
      • 1-2-3-4-1 (O)
      • 1-2-3-2-4 (X)
  • Cycle
    • 起點與終點相同的 Single Path
    • ex: 1-2-3-4-1
  • Connected (連通)
    • 對無向圖而言,任意頂點對之間皆有 Path 存在
    • Tree 可視為一個 Connected 無向圖
      • Connected 無向圖不可視為一顆 Tree: 可能會有 cycle
      • 無 cycle 無向圖不可視為一顆 Tree: 可能不連通
  • Connected Component (連通子圖)
  • Strongly Connected (強連通)
    • 對無向圖而言,任意頂點對 (i,j)(i,j) 滿足:
      • ii 有 Path 可到達 jj
      • jj 有 Path 可到達 ii
  • Strongly Connected Component (強連通子圖)
  • Degree (分支度)
    • 無向圖: 該頂點連結的邊數
      • ∣E∣=12∑Degree|E| = \frac{1}{2}\sum{Degree}
    • 有向圖分為:
      • Out-Degree (出支度): 頂點射出之邊數
      • In-Degree (入支度): 射入頂點之邊數
      • ∣E∣=∑OutDegree=∑InDegree|E| = \sum{OutDegree}= \sum{InDegree}

Graph 的表示方法

Adjacency Matrix (相鄰矩陣)

  • 令 G=<V,E>, ∣V∣=nG = <V,E>,~|V| = n,則準備一個 matrix A:n∗nA:n * n,其中 A[i,j]=A[i, j]=
    • 1, if1,~\text{if} 邊 (i,j)(i,j) 存在
    • 0, if0,~\text{if} 不存在
  • 無向圖
    • 相鄰矩陣必為對稱矩陣 (Symmetric)
      • (i,j)=(j,i)⇒A[i,j]=A[j,i](i,j) = (j,i) \Rightarrow A[i,j] = A[j,i]
    • 判斷邊是否存在: O(1)O(1)
      • 查 A[i,j]A[i,j]
    • 求頂點 ViV_i 之 degree: O(n)O(n)
      • 查第 ii 行/列元素和
    • 求圖之邊數: O(n2)O(n^2)
      • 12∑Degree=12∑∑A[i,j]\frac{1}{2}\sum{Degree} = \frac{1}{2}\sum{\sum{A[i,j]}}
  • 有向圖
    • 行為 In-Degree,列為 Out-Degree
    • 相鄰矩陣不一定為對稱矩陣 (Symmetric)
    • 判斷邊是否存在: O(1)O(1)
    • 求頂點 ViV_i 之 In/Out-degree: O(n)O(n)
      • 查第 ii 行/列元素和
    • 求圖之邊數: O(n2)O(n^2)
      • ∑InDegree=∑OutDegree=∑∑A[i,j]\sum{InDegree} = \sum{OutDegree} = \sum{\sum{A[i,j]}}

Adjacency Lists (相鄰串列)

  • 令 G=<V,E>, ∣V∣=n, ∣E∣=eG = <V,E>,~|V| = n,~|E| = e,則準備 nn 條相鄰串列,以 Vertex[1...n]Vertex[1...n] of pointer 表示,其中 Vertex[i]Vertex[i] 代表 ViV_i 之相鄰串列,記錄所有與 ViV_i 相鄰之頂點編號
    • Node: Vertex No. | Next (Link)
  • 無向圖
    • 所有相鄰串列之 Node 總數 = 2∣E∣2|E|
      • 一條邊會加入兩個相鄰串列的 Node
    • 判斷邊是否存在: O(Vi 串列長度)≤O(∣E∣)O(V_i~\text{串列長度}) \leq O(|E|)
      • 檢查 Vertex[i]Vertex[i] 串列中是否存在 Node VjV_j
    • 求頂點 ViV_i 之 degree: O(Vi 串列長度)≤O(∣E∣)O(V_i~\text{串列長度}) \leq O(|E|)
      • 求 Vertex[i]Vertex[i] 串列長度
    • 求圖之邊數: O(∣V∣+∣E∣)O(|V|+|E|)
      • 12∑Degree=12∑Vi 串列長度\frac{1}{2}\sum{Degree} = \frac{1}{2}\sum{V_i~\text{串列長度}}
  • 有向圖
    • 所有相鄰串列之 Node 總數 = ∣E∣|E|
    • 判斷邊是否存在: O(Vi 串列長度)≤O(∣E∣)O(V_i~\text{串列長度}) \leq O(|E|)
    • 求頂點 ViV_i 之 degree:
      • Out-Degree: O(Vi 串列長度)≤O(∣E∣)O(V_i~\text{串列長度}) \leq O(|E|) 求 Vertex[i]Vertex[i] 串列長度
      • In-Degree: O(∣V∣+∣E∣)O(|V|+|E|) 求所有串列中 Node ViV_i 出現次數
    • 求圖之邊數: O(∣V∣+∣E∣)O(|V|+|E|)
      • ∑OutDegree=∑Vi 串列長度\sum{OutDegree} = \sum{V_i~\text{串列長度}}

比較表

  • 令 G=<V,E>, ∣V∣=n,, ∣E∣=eG = <V,E>,~|V| = n,,~|E| = e
Adjacency Matrix Adjacency Lists
空間需求 O(n2)O(n^2) O(n+e)O(n+e)
邊數少 不適合 (稀疏矩陣) 適合
邊數多 適合 不適合
判斷邊是否存在 適合 O(1)O(1) 不適合 O(e)O(e)
求邊數、連通與否… 不適合 O(n2)O(n^2) 適合 O(n+e)O(n+e)

Adjacency Multilists (相鄰多元陣列)

  • 令 G=<V,E>, ∣V∣=n,, ∣E∣=eG = <V,E>,~|V| = n,,~|E| = e,圖中的每條邊用一個 Node 來表示
    • Node: ViV_i | VjV_j | Link for ViV_i | Link for VjV_j
      • Link for ViV_i: 指向下一個包含 ViV_i 的 Node
      • Link for VjV_j: 指向下一個包含 VjV_j 的 Node
    • 另準備一個 Vertex[1...n]Vertex[1...n] of pointer,其中 Vertex[i]Vertex[i] 指向第一個包含 ViV_i 的 Node
  • 空間需求: O(∣V∣+∣E∣)O(|V|+|E|)

Index Array

  • 用一個 Array 紀錄所有點之相鄰節點編號,且用一個 Index 告知其起始位置
  • 空間需求: O(∣V∣+∣E∣)O(|V|+|E|)

Incident Matrix

  • 令 G=<V,E>, ∣V∣=n,, ∣E∣=eG = <V,E>,~|V| = n,,~|E| = e,則準備一個 matrix A:n∗eA:n * e
    • 若 eke_k 邊為 (i,j)(i,j),則 A[i,ek]=A[j,ek]=1A[i, e_k] = A[j, e_k] = 1,其餘為 0

Graph Traversal

拜訪圖中每個頂點各一次

DFS

  • 以無向圖為例
1
2
3
4
5
6
7
8
9
10
for i = 1 to n{
visited[i] = false
}

DFS(v: start vertex){
visited[v] = true
for each vertex w adjacent to v{
if(!visited(w)) DFS(w)
}
}
  • DFS order 並非唯一
    • 通常會規定依 vertex No. 小者優先走訪,如此 order 唯一

邊分類

  • 當使用 DFS 進行有向圖的遍歷,可以將邊分為 4 類:
    • Tree edge: 遍歷追蹤時所經過的邊
      • 指向的 vertex 為還未遍歷過的 (white)
    • Back edge: 指向自己的祖先
      • 指向的 vertex 為已遍歷過,但尚未 DFS 完成 (gray)
    • Forward edge: 指向自己的後代
      • 指向的 vertex 為已遍歷過,且 DFS 完成 (black)
      • discovered time 比自身晚 (大)
    • Cross edge: 指向與自己無關的 vertex
      • 指向的 vertex 為已遍歷過,且 DFS 完成 (black)
      • discovered time 比自身早 (小)
  • 遍歷順序為: u→v→y→x→w→zu \rightarrow v \rightarrow y \rightarrow x \rightarrow w \rightarrow z

  • 當使用 BFS 進行有向圖的遍歷,可以將邊分為 2 類:

    • Tree edge: 遍歷時所經過的邊
    • Back edge: 遍歷時沒有經過的邊
      • 如果指向的點為 parent (父親),不為 Back edge

BFS

  • 以無向圖為例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
for i = 1 to n{
visited[i] = false
}

BFS(v: start vertex){
visited[v] = true
queue Q
Q.push(v)
while(!Q.empty()){
u = Q.front()
Q.pop()
for each vertex w adjacent to u{
if(!visited(w)){
visited[w] = true
Q.push(w)
}
}
}
}
  • BFS order 並非唯一
    • 通常會規定依 vertex No. 小者優先走訪,如此 order 唯一

比較表

DFS BFS
資料結構 Stack Queue
時間 (Adjacency Matrix) O(n2)O(n^2) O(n2)O(n^2)
時間 (Adjacency Lists) O(e)O(e) / O(n+e)O(n+e) O(e)O(e) / O(n+e)O(n+e)
  • 對於二元樹而言
    • DFS: 類似 Preorder Traversal
    • BFS: 類似 Level-order Traversal

Spanning Tree (展開樹/生成樹)

  • 給定一個 connected 無向圖 G=<V,E>G = <V,E>,令 S=<V,T>S = <V,T> 是 GG 的一個 Spanning Tree,則 SS 滿足:
    • E=T+BE = T + B
      • EE 為 Tree edge
      • BB 為 Back edge
    • 在 SS 中,任何頂點對之間,只存在一條 (unique) simple path
    • 若自 BB 中任取一邊加入 SS 中,必定會形成一個 (unique) cycle
  • 若 GG 為 unconnected,則沒有 Spanning Tree
  • 若 GG 為 connected,則 Spanning Tree≥1\geq 1棵
  • 若 GG 的頂點數為 $ n$,則其 Spanning Tree 的邊數必為 n−1n - 1
  • 一個 connected 無向圖 GG 的任意兩個 Spanning Tree (若存在) 必有共同邊?
    • False: 不一定
    • 反例: 4 個頂點的完全圖 (Z 字形連接)

Minimum Spanning Tree (最小生成樹)

  • 給定一個 connected 無向圖 G=<V,E>G = <V,E>,其邊上附有成本 (加權) 值,則在 GG 的所有 Spanning Tree 中具有最小的邊成本總和者
  • 若圖中有多條邊具有相同成本,則 Minimum Spanning Tree 可能 ≥1\geq 1棵
  • 若圖中每條邊之成本皆不同 (unuque),則 Minimum Spanning Tree 唯一
  • 求 Spanning Tree 之演算法 (Greedy strategy):
    • Kruskal’s Algorithm
    • Prim’s Algorithm
    • Sollin’s Algorithm

Kruskal’s Algorithm

  • 給定一個 connected 無向圖 G=<V,E>G = <V,E>
  • Steps:
    1. 自 EE 中挑出最小成本的邊 (u,v)(u,v)
    2. 判斷 (u,v)(u,v) 加入 Spanning Tree SS 中是否會形成 cycle
      • 無 cycle: (u,v)(u,v) 加入 SS 中
      • 有 cycle: 放棄 (u,v)(u,v)
    3. 重複 1.2. 直到挑出 ∣V∣−1|V| - 1 條邊,或 EE 為空
    4. (可省) 若 SS 中邊數 ≤∣V∣−1\leq |V| - 1,則 GG 沒有 Spanning Tree
  • 時間複雜度
    • 最多執行 ∣E∣|E| 輪
      • Delete-min cost edge (u,v)(u,v) from EE
      • 判斷 (u,v)(u,v) 加入 SS 是否造成 cycle
    • Delete-min 若使用 Heap 保存各邊成本,則需要 O(log⁡∣E∣)O(\log{|E|})
    • cycle 檢查利用 Disjoint Set 的 Union, Find 操作,約需要 O(1)O(1)
      • 假設採用 Union-by-Height, Find-with-path-Compression
      • 檢查 Find(u)Find(u) 與 Find(v)Find(v) 的值是否相同 (屬於相同 set 會造成 cycle)
      • (u,v)(u,v) 加入 SS 中: Union(u,v)Union(u,v)
    • 總時間為 ∣E∣∗(O(log⁡∣E∣)+O(1))=O(∣E∣log⁡∣E∣)|E| * (O(\log{|E|}) + O(1)) = O(|E|\log{|E|})
      • ∣E∣<∣V∣2⇒O(∣E∣log⁡∣V∣)|E| < |V|^2 \Rightarrow O(|E|\log{|V|})

Prim’s Algorithm

  • 給定一個 connected 無向圖 G=<V,E>,V=1,2,3...,nG = <V,E>, V = 1,2,3...,n,令 U=1U = {1} (代表起始 vertex,可以隨意選擇)
  • Steps:
    1. 挑出最小成本的邊 (u,v)(u,v),其中 $u \in U$ 且 $v \in V-U$
    2. (u,v)(u,v) 加入 SS 中,且將 vv 自 V−UV-U 中移入 UU
    3. 重複 1.2. 直到 U=VU=V
  • 時間複雜度
    • use Adjacency Matrix: O(∣V∣2)O(|V|^2)
    • use Heap: O(∣E∣log⁡∣V∣)O(|E|\log{|V|})
    • use Fibonacci Heap: O(∣V∣log⁡∣V∣+E)O(|V|\log{|V| + E})

Sollin’s Algorithm

  • 一開始把每個頂點視為一個獨立的樹之 Root
  • Steps:
    1. 從每棵樹中挑出最小成本之 Tree edge
    2. 刪除重複挑出的邊,只保留一份
    3. 重複 1.2. 直到只剩下一棵樹

最短路徑問題

Dijkstra’s Algo Bellmen-Ford Algo Floyd-Warshall Algo
解決問題 單源最短路徑 單源最短路徑 全域最短路徑
策略 Greedy DP DP
Time O(V2)O(V^2) O(V3)O(V^3) O(V3)O(V^3)
圖是否可有負邊 不可 可 可
圖是否可有負 cycle 不可 不可 不可

Dijkstra’s Algorithm

  • 給定一個 有向圖 G=<V,E>, ∣V∣=nG = <V,E>,~|V| = n,,其邊上附有cost (length) 值
  • 使用的資料結構
    • Cost Matrix: 一個 n∗nn * n 的 Matrix,其中 Cost[i,j]=Cost[i,j] =
      • 邊成本值, if<i,j>∈E,~\text{if} <i,j> \in E
      • 0, if i=j0,~\text{if}~i = j
      • ∞, if<i,j>∉E\infty,~\text{if} <i,j> \notin E
    • S: [1,2,...,n]S:~[1,2,...,n] of Boolen,其中 S[i]=S[i]=
      • False (0): 起點到 ii 點之最短路徑尚未確定
      • True (1): 起點到 ii 點之最短路徑已確定
      • 初值皆為 False
    • Dist: [1,2,...,n]Dist:~[1,2,...,n] of Int,其中 Dist[i]=Dist[i]=
      • 起點到 ii 點之最短路徑長
      • 初值為 Cost Matrix 中起點那一列元素值
  • Steps:
    1. 自尚未確定最短路徑的點 (S[i]==0S[i] == 0) 中,挑出 Dist 最小的點,令其為 uu,並設定 S[u]=1S[u] = 1
    2. 對於 uu 的所有相鄰點 ww,如果 $S[w] == 0 $,則檢查是否可以優化其 Dist (Relax) (經過 uu 到達 ww 距離更短)
    3. 重複 1.2. n−2n - 2 次
  • 重要假設條件: 無負邊,否則可能無法求出正確值
  • 可以額外建立一個 array 儲存各點之 parent,方便回推最短路徑
  • 時間複雜度 [Algo]
    • use Heap: O(∣E∣log⁡∣V∣)O(|E|\log{|V|})
    • use Fibonacci Heap: O(∣V∣log⁡∣V∣+E)O(|V|\log{|V| + E})
    • 與 Prim's Algorithm 相同: Base on BFS concept

Bellmen-Ford Algorithm

  • 給定一個 有向圖 G=<V,E>, ∣V∣=nG = <V,E>,~|V| = n,,其邊上附有cost (length) 值
  • 定義: DistK: [1,2,...,n]Dist^K:~[1,2,...,n] of Int,其中 DistK[i]=Dist^K[i]=
    • 起點到 ii 點之最短路徑長 且經過的邊數 ≤K\leq K
    • Dist1Dist^1 為初值,數值為 Cost Matrix 中起點那一列元素值
  • Steps:
    • 依序求出 Dist2,Dist3...Distn−1Dist^2,Dist^3...Dist^{n - 1},Distn−1Dist^{n - 1} 即為結果
      • 針對 DistK[i]Dist^K[i],對每個指向 ii 的邊進行檢查是否能 Relax
  • 時間複雜度
    • O(∣V∣3)O(|V|^3)
    • O(∣V∣∗∣E∣)O(|V| * |E|) [Algo]
  • 檢查是否有 負 cycle
    • 跑完正常的 Bellmen-Ford Algo (n - 1 輪)
    • 再跑一輪,如果有 Distn[i]Dist^n[i] 可以 Relax,則存在 負 cycle

Floyd-Warshall Algorithm

  • 給定一個 有向圖 G=<V,E>,V=1,2,3...,nG = <V,E>, V = 1,2,3...,n
  • 定義: AKA^K: 一個 n∗nn * n 的 Matrix,其中 AK[i,j]=A^K[i,j]=
    • ii 到 jj 之最短路徑長,且途中經過的頂點編號必須 ≤K\leq K
    • A0A^0 為初值,同 Cost Matrix
  • Steps:
    • 依序求出 A1,A2...AnA^1,A^2...A^n,AnA^n 即為結果
      • 針對 AK[i,j]A^K[i,j],進行檢查是否能 Relax (i→j or i→k→ji\rightarrow j~\text{or}~i\rightarrow k\rightarrow j)
  • 時間複雜度
    • O(∣V∣3)O(|V|^3)

A+, A∗A^+,~A^* 矩陣

  • 給定一個 有向圖 G=<V,E>, ∣V∣=nG = <V,E>,~|V| = n
  • A+A^+ 矩陣: Transitive Closure Matrix
    • 一個 n∗nn * n 的 Matrix,其中 A+[i,j]=A^+[i,j]=
      • 1, if1,~\text{if} ii 到 jj 有 path,且長度 ≥1\geq 1
      • 0, otherwise0,~\text{otherwise}
  • A∗A^* 矩陣: Reflexive-Closure Matrix
    • 一個 n∗nn * n 的 Matrix,其中 A∗+[i,j]=A*+[i,j]=
      • 1, if1,~\text{if} ii 到 jj 有 path,且長度 ≥0\geq 0
      • 0, otherwise0,~\text{otherwise}
  • A∗=A+∪IA^* = A^+ \cup I (單位矩陣)

AOV Network & Topological sort

AOV (Activity On Vertex) Network

  • 給定一個 有向圖 G=<V,E>G = <V,E>,代表 AOV Network,其中:
    • Vertex: 代表工作 (Activity)
    • Edge: 代表工作執行之先後順序
      • i→ji \rightarrow j 存在代表 ii 必須先於 jj 執行
  • 用於判斷計畫工作間的執行是否合理,即至少要有 ≥1\geq 1 組合理的工作順序 (Topological sort)

Topological sort

  • 給予一個不具 cycle 的 AOV Network,則至少可以產生 ≥1\geq 1 組合理的頂點拜訪順序,滿足:
    • 在 AOV Network 中,若 ii 有 path 到達 jj,則在此順序中, ii 必定出現在 jj 之前
  • Steps:
    1. 找出 In-degree == 0 之 Vertex ii
    2. 輸出 ii 且刪除從 ii 射出的邊
    3. 重複 1.2. 直到所有點都已經輸出,或是沒有 In-degree == 0 之 Vertex
      • 如果不是所有點皆已經輸出,則無 Topological sort (cycle 存在)
  • Steps [Algo]: 進行 DFS,根據 Vertex Finish 的時間由後往前排序

AOE Network & critical path & critical task

AOE (Activity On Edge) Network

  • 給定一個 有向圖 G=<V,E>G = <V,E>,代表 AOE Network,其中:
    • Vertex: 代表事件 (Event)
    • Edge: 代表工作 (Activity)
    • Edge 上數字: 代表工作完工所需天數
  • 意義:
    • 所有射入事件 Vertex 之工作皆完成後,事件才會發生
    • 事件發生後,從該 Vertex 射出之工作才可以開工
  • 用於計畫之專案管理
  • 求完成計畫之最短天數: critical path 之長度
    • start 到 end 之最長路徑長
    • critical path 可能有多條
    • critical task 上的所有工作
  • 要加速哪些工作可以有效縮短計畫完工天數:
    • 所有 critical path 上的交集 (共同) 工作
  • 哪些工作可以 delay,又可以 delay 多久不影響進度
    • 不在 critical path 上的工作皆可 delay
    • delay 時間:
      • 先求各事件之最早發生時間: start 到各點之最長路徑長
      • 再求各事件之最晚發生時間: 從 end 往回推各點
      • 求各工作之最早開工 (前一事件的最早發生時間)、最晚開工時間 (後一事件的最晚發生時間),根據兩者之差距求得

Articulation Point

  • 在一個 connected 無向圖 中,若刪除某頂點及其連結的邊,則剩下的圖變為 unconnected,該點稱之為 Articulation Point
  • Biconnected Graph:
    • 一個不具有 Articulation Point 之 connected 無向圖
  • Biconnected Component:
    • 給定一個 connected 無向圖 G=<V,E>G = <V,E>,令 G′G' 是 GG 的一個子圖,且滿足:
      • G′G' 是 Biconnected Graph
      • G′G' 是 Max Component (沒有其他 Biconnected Graph 子圖可包含 G′G')
  • 求 Articulation Point:
    • 從某點開始做 DFS,求各點之 dfn (DFS Number: 拜訪順序)
    • 畫出 DFS Spanning Tree 且標示出 Back edge
    • 求出各點之 low 值:
      • low(x)=min(dfn(x),{dfn(y) ∣ y 為 x 的後代 (含 x) 中最多經過一條 Back edge 所到之點})low(x) = min(dfn(x), \{dfn(y)~|~y~\text{為}~x~\text{的後代}~(\text{含}~x)~\text{中最多經過一條}~\text{Back}~\text{edge}~\text{所到之點}\})
    • 判斷規則:
      • 對於 root,若其有 ≥2\geq 2 個子點,則為 Articulation Point,否則不是
      • 對於 非 root 頂點 xx,令 yy 為 xx 之任一子點,若存在 low(y)≥dfn(x)low(y) \geq dfn(x) 則 xx 為 Articulation Point