105 年台大電機丙資結
===
>有錯歡迎留言指正
一、
1. B
2. B
3. A
4. B
5. B
6. A
7. A
8. B
9. A
10. B
11. C
12. C
13. E
14. E
三、懶得寫
四、
可能還有更快的解法但我想不到 Q
**直覺解法** :
定義一個 n * n 二維陣列 arr 儲存 $f(a_i, a_j)$ 之值。
CreateTable(arr) : 計算所有 $f(a_i, a_j)$ 之值,同時間紀錄最小值。時間複雜度為 $O(n^2)$。
```=1
min = ∞
for i = 1 to n
for j = 1 to n
arr[i][j] = f(a_i, a_j)
if arr[i][j] < min
min = arr[i][j]
```
Update($a_i$, value): 每當 $a_i$ 要更新成 value 時,就呼叫此函數。此函數會更新 $f(a_i, a_j)$ 和 $f(a_j, a_i)$ for j = 1 ~ n,共 2n 筆資料,時間複雜度為 $O(n)$。
```=1
a_i = value
for j = 1 to n
arr[i][j] = f(a_i, a_j)
arr[j][i] = f(a_j, a_i)
```
題目要求更新 m 次資料,所以從建立二維陣列到完成 m 次更新所需之時間為 $O(n^2+mn)$。
若 m > n,則時間為 $O(mn)$;若 m <= n,則時間為 $O(n^2)$。
五、
利用 Tarjan's 演算法
1. DFS
2. 拜訪階段,針對每點,計算自己和子孫所能觸及的最高祖先。觸及是指 : 不斷走任意邊但不能走到曾經形成的 SCC。
3. 回溯階段,每當發現某點恰是最高祖先,即表示這點和子孫已形成 SCC。從堆疊中刪除 SCC 免得再次處理。
令 adj[n][n] 為 adjacency matrix
令 visit[n] 表示拜訪該節點的時間
令 Instack[n] 紀錄該點是否在堆疊中
```=
DFS(i, parent){
visit[i] = low[i] = True
time++
stack.push(i)
for i = 1 to n
if(adj[i][j])
if(visit[j] == 0) DFS(j, i)
if(j != parent) low[i] = min(low[i], low[j])
if(visit[i] = low[i])
do
k = stack.pop()
print(k)
while(i != k)
}
```
時間為一次 DFS 走訪的時間,且用 adjacency matrix,故為 $O(V^2)$