# Graph
圖論在計算機領域中佔有非常重要的一個地位
現在考研發現包刮離散、演算法、資結甚至OS都會用到
做一篇大統整
## 表示法
1. Adj Matrix
強連通圖的Adj Matrix為symmetric
邊數多的時候適合
2. Adj List
邊數少的時候適合
## 圖的種類及術語
* 分為有向圖及無向圖,$\{a,b\}=\{(a,b),(b,a)\}$,每個無向邊可視為兩個有向邊的集合
* multigraph: 存在$a,b\in V$使得a,b之間至少兩個邊,兩個點之間的邊數稱為重數multiplicity,邊集合會是multiset(有重複元素)
**基本術語**
| 名詞 | 定義 | 備註 |
| ----------- | -------------------------- | ---- |
| walk 路 | 從$v_i$到$v_j$經過的點集合 | |
| closed walk | 起點終點相同的walk | |
| trail 路線 | **不含重複邊**的walk | |
| path 路徑 | **不含重複點**的walk | 不含重複點就不會含重複邊,所以path也會是trail |
| circuit 迴路 | closed trail | 至少含一點 |
| cycle環路 | closed path | 至少含三點,cycle也會是circuit |
* $2*|E|=\sum_{i=0}^{n-1}deg(v_i)$
* 計算有向圖的in degree和out degree
利用adj list,$\Theta(n^2)$
利用adj matrix,$\Theta(n^2)$
```c=
//Adj list
Out_Deg(G){
for each u in G.V
u.out_deg=0
for each v in G.Adj[u]
u.out_deg+=1
}
In_Deg(G){
for each u in G.V
u.in_deg=0
for each u in G.V
for each v in G.Adj[u]
v.in_deg+=1
}
//Adj matrix,n是點的數量
Out_Deg(G,n){
for each u in G.V
u.out_deg=0;
for(int i=0;i<n;i++)
if(G.AdjM[u.id][i])
u.out_deg+=1;
}
In_Deg(G,n){
for each u in G.V
u.in_deg=0;
for(int i=0;i<n;i++)
if(G.AdjM[i][u.id])
u.in_deg+=1;
}
```
* 對任意無向圖,奇數點的點數必有偶數個
* 對於有向圖來說,$\sum_{v\in V}InDeg(v)=\sum_{v\in V}OutDeg(v)$ (因為in degree和out degree成對出現)
$2*|E|=\sum_{v\in V}InDeg(v)+\sum_{v\in V}OutDeg(v)$
$|E|=\sum_{v\in V}InDeg(v)=\sum_{v\in V}OutDeg(v)$
* 若$G=(V,E)$為simple graph,若每個vertex度數至少2,則$G$包含一個環路
若每個vertex度數至少$k$,則$G$包含一個長度至少$k+1$的環路 (證明)
- [ ] cycle detection algorithm(using DFS)
透過DFS來偵測是否有back edge,有就代表有cycle
- [ ] deadlock avoidance algorithm
* **DAG**: directed acyclic graph, 有向且無迴圈的圖
每個DAG都一定有自己的Topological sorting(不一定唯一)
```c=
Topological_Sort(G){
DFS(G);//compute finish time v.finish for every vertex
當vertex完成搜尋時(產生v.finish),把它插入到linked list的最前方
return LList; //如果回傳的list length不等於|G.V|,代表此圖不是DAG
}
```
### 連通圖
| 名詞 | 定義 | 備註 |
| -------- | -------- | -------- |
| Connected Graph| (無向圖)$\forall x,y\in V,x\neq y$,存在由$x$到$y$的path | 連通圖: $\kappa(G)=1$,不連通圖: $\kappa(G)\ge 2$ |
| Strongly Connected Graph 強連通圖| (有向圖) 任意兩點間都存在有向path能互相到達| 邊數一定是偶數 |
| Unilaterally Connected Graph 單方向連通圖 | (有向圖) 任意兩點間存在path能從一點到另一點 | 強連通圖一定是單方向連通圖 |
| Weakly Connected Graph 弱連通圖 | 把有向圖的邊全部換成無向之後會是連通圖 | 把有向圖的邊全部換成無向之後會是連通圖,單方向連通圖必為弱連通圖,所以強連通圖也必為弱連通圖 |
|Strictly unilaterally connected Graph 嚴格單方向連通圖| 單方向連通圖但不為強連通圖 ||
|Strictly weakly connected graph 嚴格弱連通圖| 弱連通圖但不為單方向連通圖 | |
* 假設$|V|=n$,則滿足$G$為connected的最少邊數為$n-1$,同時也是一顆tree,所以一個graph的spanning tree會是一個graph的minimal connected subgraph
* 若$G=(V,E)$為一個undirected connected graph且$|V|\ge 1$,則$|E|\ge |V|-1$
* 假設$A$為$G$的adj matrix,則$A^r$的第$i,j$項為$v_i$到$v_j$長度為$r$的path的個數
* **找Strongly connected component的算法**
做兩次DFS
*把第二次得出的每個SCC當成一個node,cross edge當成邊,可以得到一個DAG*
```c=
SCC(G){
DFS(G);//compute v.finish
G.T = Transpose(G);
DFS(G.T); //按照第一次DFS算出的finish time的decreasing order來造訪G.V
//在第二次DFS中,每次產生的一個tree都是一個SCC
}
```
* 假設一個圖中有兩個SCC,C、C',那$f(C)>f(C')$或$f(C')>f(C)$兩者必有一個成立,也就是其中一個SCC的vertexs的finish time一定都大於另一個SCC的finish time (證明)
<img src="https://i.imgur.com/JIiZt4p.png">
### 子圖 subgraph
原圖為$G=(V,E)$
| 名詞 | 定義 | 備註 |
| -------- | -------- | -------- |
| Subgraph | $G'=(V',E')$滿足 $\emptyset \neq V'\subseteq V$且$E'\subseteq E\bigcap (V'\times V')$| |
| 誘導子圖 | $E'=E\bigcap (V'\times V')$ | induced subgraph on $V'$ |
| 生成子圖 | $V'=V$ | spanning subgraph |
|分量圖| $G_1=(V_1,E_1)$為$G$的誘導子圖且不存在$G$的另一個誘導子圖$G_2=(V_2,E_2)$使得$V_1\subset V_2$ | $G$的分量圖個數記做$\kappa(G)$ |
- [ ] connected component algorithm
- [ ] DAG
- [ ] Topological sorting
* 圖的聯集
$G_1,G_2$為兩個無向簡單圖,$G_1\bigcup G_2=(V_1\bigcup V_2,E_1\bigcup E_2)$
* $G-v$表示去除掉點$v$還有和$v$相連的邊
$G-e$表示去掉邊$e$就好
| 名稱 | 定義 | 備註 |
| -------- | -------- | -------- |
| 切點 | $v\in V$滿足$G_1=(V-\{v\},E_1)$使得$G_1$為不連通圖 | cut point、articulation point |
| 切集 | 邊集$E_1\subseteq E$滿足$G_1=(V,E-E_1)$使得$G_1$為不連通圖,並且去掉任何$E_2\subset E_1$形成的$G_2=(V,E-E_2)$依然是連通圖 | cut set,切集不能縮小,放大之後只能說這個邊集和包含切集 |
| 切邊、橋 | 邊$e$形成切集$E_1=\{e\}$ | cut edge、bridge |
| 雙連通圖 | 一個loop free的連通無向圖且不含切點 | biconnected graph |
| 雙連通分量圖 | 一個loop free的連通無向圖可能有切點,$G$中的極大雙連通誘導子圖稱為雙連通分量圖 | biconnected component |
| 完全圖 complete graph | $K_n=(V,E)$,$\|V\|=n$,圖中任兩相異點恰有一邊相連 | $\|E\|=\dbinom{n}{2}$ |
| 有向完全圖 direct complete graph、complete tournament | 有向圖$K_n^*$ 中相異兩點$x,y$滿足$(x,y),(y,x)$洽有一邊在$G$ | 邊數為$\dbinom{n}{2}$,$K_n^*$並不唯一 |
| 雙分圖 | $G=(V,E)=(V_1\bigcup V_2,E)$, $V=V_1\bigcup V_2$ 且 $\emptyset=V_1\bigcap V_2$ | bipartite graph |
| 完全雙分圖 | 雙分圖$K_{m,n}$滿足$\|V_1\|=m,\|V_2\|=N,\forall x\in V_1,y\in V_2,\{x,y\}\in E$ | $\|E\|=mn$ |
* Biconnected Graph只有一個Biconnected component,也就是它自己
* $G$當中的兩個biconnected component頂多只會共享一個vertex,且不會共享任何邊
換言之,biconnected component會把$G$的edges給切分開
expample: $G=(V,E)$的兩個biconnected component $G_1=(V_1,E_1),G_2=(V_2,E_2)$,滿足$V_1\bigcap V_2=\{e\},E_1\bigcap E_2=\emptyset$,其中$e$為articulation point
* **怎麼找articulation point?**
先對一個graph做DFS並算出每個點的DFS number $dfn$,同時計算每個點的$low(v)$值
$low(v)$代表$v$透過自己、或自己的descendants,頂多一條back edge,能接觸到的最小$dfn$
能遞迴定義如下
$low(v)=min\{dfn(v), min\{low(x)| x.p=v\}, min\{dfn(x)|dfn(x)<dfn(v)\}\}$
情況一: root是articulation point若且唯若它有兩個以上的child(直接連接的那種)
情況二: 不為root的node $v$,若且唯若它至少有一個child $w$使得$low(w)\ge dfn(v)$
* $G$為bipartite graph $\Leftrightarrow$ $G$中不具有奇數長度的環路
<img src="https://i.imgur.com/H7nRz7R.png">
* **特殊圖**
| 名詞 | 定義 | 備註 |
| -------- | -------- | -------- |
| 規則圖 | k-regular graph,每個點的degree都是k ||
| $P_n$ | n個點的path | |
| $C_n$ | n個點的cycle ||
| $W_n$ | wheel graph,在$C_n$中加入一個新的點與$C_n$中每個點加上n個新的邊 ||
| $Q_n$ | hypercube,每個點以n個位元來表示,兩個點相鄰的條件為兩個點恰有一個位元不同,$\|V\|=2^n$,$Q_n$可由$Q_{n-1}$遞迴建構而成 | 為n-規則圖,每個點degree皆為n |
## 圖的同構
* Def:
假設$G_1=(V_1,E_1),G_2=(V_2,E_2)$為兩個simple graph,若存在一個函數$f:V_1\rightarrow V_2$滿足以下兩點,則$f$稱為isomorphism且$G_1\cong G_2$
1. $f$為one-to-one且onto function
2. $\forall a,b\in V_1,(a,b)\in E_1\Leftrightarrow (f(a),f(b))\in E_2$
若為multi graph,則還要加上每個邊的重數相同
* *同構的觀念就是重畫*
* **Graph invariant** (可用來判斷兩圖不同構,任一者不成立,即為不同構)
1. 兩圖頂點數相同
2. 兩圖邊數相同
3. 兩圖度數序列相同
4. 有相同子圖
5. 對應點距離相同
6. 對應點的連結性相同
## 圖的性質
* 對任意無向簡單圖或多重圖,奇數度數的點數必有偶數個
* maximal path: P為一條路徑且P不會包含於一個更長的路徑(即便如此,P未必是此圖中最長的路徑)
找最長路徑為NP-Complete的問題
* $G=(V,E)$為一個無向簡單圖,若$G$中每個點的度數至少k,則$G$包含一個長度至少$k+1$的環路
* $A$為一個adj matrix,$A^r$的第$(i,j)$項表示$v_i$到$v_j$長度為$r$的path的個數
* $G$為雙分圖 $\Leftrightarrow$ $G$中不具奇數長度的環路
## Graph Searching Algorithm
1. **DFS**
```c=
//recursive version
int t;
DFS(G){
for v in G.V
v.color = white;
v.parent = null;
v.start = INF; // this is also dfn
v.finish = INF;
t=0;
for v in G.V
if v.color == white
DFS_visit(G,v);
}
DFS_visit(G,u){
t += 1;
u.color = gray;
u.start = t;
for v in G.Adj[u]
if v.color == white
v.parent = u;
DFS_visit(G,v);
else if v.color == gray
print("back edge");
else if v.color == black
print("cross edge or forward edge");
u.color = black;
t += 1;
u.finish = t;
}
//iterative version
DFS(G,root){
Stack s;//init an empty stack
for v in G.V
v.parent = Null;
v.visit = false;
v.dfn = INF;
v.end = INF;
int t=0;
s.push(root);
while(!s.empty()){
t +=1;
u = s.top();
if(u.visit){
s.pop();
u.end = t;
continue;
}
u.visit = true;
u.dfn = t;
for v in G.Adj[u]
if !v.visit
v.parent = u;
s.push(v);
}
}
```
2. **BFS**
```c=
BFS(G,root){
for v in G.V
v.parent = NULL;
v.visit = false;
Queue q; //init an empty queue
q.push(root);
while(!q.empty()){
u = q.top();
q.pop();
u.visit = true;
for v in G.Adj[u]
if !v.visit
v.parent = u;
q.push(v);
}
}
```
3. **Best First Search**
* 不使用普通的queue或stack,使用priority queue,過程跟BFS有點相似,但換成使用priority queue,priority可以用邊的權重表示或者點的權重
```c=
Best_FS(G,root,goal){
for v in G.V
v.parent = NULL;
v.visit = false;
Priority_Queue pq; //init an empty queue
pq.push(root);
root.visit = true;
while(!pq.empty()){
u = pq.top();
pq.pop();
if(u == goal)
return;
for v in G.Adj[u]
if !v.visit
v.parent = u;
v.visit = true;
pq.push(v);
}
}
```
## Minimum Spanning Tree
* 問題描述: 若給一個連通圖上的每個邊weight,如何得到此圖具有最小weight的spanning tree?
* 暴力法: 最糟情況若此圖有n(n-1)條邊,則可能的spanning tree有$\dbinom{n^2-n}{n}$種可能
* 思考: 如果我們已經有此圖的MST的子集,A,要怎麼挑選edge加入A才能保證$A\bigcup e$同樣也是MST的子集?
將點分為兩邊,$(V_1,V-V_1)$稱為一個cut,挑選跨越此cut上weight最小的邊,可以稱它為light edge、safe edge,將此邊加入A可以保證加入後還是MST的子集
透過不同尋找light edge的方法(不同的方法來製造cut),可以有以下幾種找MST的算法
### Kruskal algorithm
* 做法: 每次挑選連接不同set中的edge裡,weight最輕的那個,並將兩個set合併(算法執行的時候可以有超過兩個set,數個cut存在)
一開始先將每個點都做成一個set,並把edge依照weight排序,然後重複上述步驟直到把所有edge檢查完
*會用到union、find*
```c=
Kruskal(G,w){
A=NULL;
for each v in G.V
Make_set(v);
sort(G.E,w);//將edge依照weight,nondecreasing order排序
for each edge (u,v) in G.E
if Find_Set(u)!=Find_Set(v) //light edge
A = A+(u,v);
Union(u,v);
return A;
}
```
* 此算法的時間複雜度取決於我們怎麼實作set這個data structure,如果我們用disjoint set的方式,那時間複雜度可以降到$\Theta(|E|lg|V|)$
### Prim's Algorithm
* 也就是這算法做cut的方式都是$(A.V,V-A.V)$,每次選取此cut上的light edge,這是一個greedy algorithm
```c=
Prim(G,w,root){
A=NULL;
for each v in G.V
v.key = INF;
v.parent = NULL;
root.key = 0;
Queue Q = G.V;
while(!Q.empty()){
u = Q.Extract_Min();
for each v in G.Adj[u]
if v in Q and w(u,v) < v.key
v.key = w(u,v);
v.parent = u;
}
}
```
* 時間複雜度取決我們怎麼實作queue,如果使用binary min_heap,則會是$\Theta(ElgV)$,如果用Fibonacci heap,會是$\Theta(E+VlgV)$
- [ ] 經典問題: second best MST
- [ ] Bottleneck spanning tree
## Single-source Shortest Path Algorithms
* 給定一起點s,如何求得s到各點的最短路徑
* **shortest path的subpath也是shortest path**
<img src="https://i.imgur.com/cJS8KsE.png">
* 每個shortest path頂多有$|V|-1$條邊,更多的話代表有cycle,negative cycle的話shortest path length會是負無限大,而positive cycle不可能出現在shortest path裡面,0-weight cycle則是可以忽略
* shortest path spanning tree肯定也是MST嗎? 不是,有反例
* 最短路徑的算法都有以下重要特性
- **Triangle inequality**: $\forall (u,v)\in E,\delta(s,v)\le \delta(s,u)+w(u,v)$
<img src="https://i.imgur.com/ohG0BGt.png">
- **Path-relaxation property**: 如果$p=<v_0,...,v_k>$為$v_0$到$v_k$的shortest path,並且我們依照$(v_0,v_1),..,(v_i,v_{i+1}),..,(v_{k-1},v_k)$的順序relax他們,則$v_k.d=\delta(v_0,v_k)$
### Bellman-Ford Algorithm
* 可以有負邊
* 時間複雜度$\Theta(|V||E|)$
* 做$|V|-1$次迴圈是因為shortest path頂多$|V|-1$條邊,不管edge被嘗試relax的順序是如何,被成功relax的順序一定有按照$v_0,..,v_k$,最外圈第i次迴圈(有可能提前)一定會relax到$(v_{i-1},v_i)$,透過path-relaxation property知道,照順序把整個shortet path上的點都relax過的話可以確定找到shortest path
```c=
//G is graph, w is weight function, s is the source
Bellman_Ford(G,w,s){
for v in G.V
v.d=INF;
v.parent=NULL;
s.d=0;
bool relax;
for i=1:|G.V|-1
relax=false;
for each (u,v) in G.E
if v.d>u.d+w(u,v)
v.d=u.d+w(u,v);
v.parent=u;
relax = true;
if !relax
break;
for each (u,v) in G.E
if v.d>u.d+w(u,v)//negative cycle exists
return false;
return true;
}
```
* 可利用dp來做bellman-ford
$v_0=s$
$d^k[j]$表示$s$到$v_j$不走超過$k$個邊的shortest path length
$d^k[j]=\begin{cases}
w[0,j] \ \ if \ \ k=1\\
min\{d^{k-1}[j],min(d^{k-1}[i]+w[i,j])\} \ \ k>1
\end{cases}$
* 由於path relaxation property,如果我們可以按照順序relax每個邊,只需要把每個邊都relax一次就可以得出shortest path
用topological sort就可以找到這個順序(前提是此圖為DAG)
Time Complexity: $\Theta(V+E)$
```c=
DAG_Shortest_Path(G,w,s){
TopoSort(G);
Init(G,s);
for each u in G.V//now in topological sorting order
for each v in G.Adj[u]
if v.d>u.d+w(u,v)
v.d=u.d+w(u,v)
}
```
### Solving systems of difference constraints
* 一個線性系統每個長的像$x_j-x_i\le b_k$
* 思考三角不等式$\delta(v)\le \delta(u)+w(u,v)$,所以$\delta(v)-\delta(u)\le w(u,v)$,因此將每個變數看成一個vertex,並新增一個source vertex s,到各點的距離都為0,到每個點的shortest path length就會是一組解
### Dijkstra's Algorithm
* 不能有負邊
* 集合S當中的vertex的shortest path都已經確定了
* Greedy strategy
```c=
Dijkstra(G,w,s){
for each u in G.V
u.d = INF;
u.parent = NULL;
s.d = 0;
S = Init_Set(); //init an empty set
Q = Queue(G.V);
while (!Q.empty()){
u = Q.Extract_Min();
S += u;
for each v in G.Adj[u]
if(v.d>u.d+w(u,v))
v.d=u.d+w(u,v);
v.parent = u;
}
}
```
* 時間複雜度取決於我們如何實作此Min queue,用binary heap會是$\Theta(ElgV)$,用Fibonacci heap會是$\Theta(VlgV+E)$
## All pairs shortest path
* 會記錄一個predecessor matrix,$\prod=(\pi_{ij})$,$\pi_{ij}$代表i到j的shortest path上,j的predecessor
所以由這個matrix的第i個row所產生的subgraph就是以i為root的predecessor subgraph $G_{\pi,i}=(V_{\pi,i},E_{\pi,i})$,且$V_{\pi,i}=\{j\in V:\pi_{ij}\neq NIL\}\bigcup \{i\}, E_{\pi,i}=\{(\pi_{ij},j):j\in V_{\pi,i}-\{i\}\}$
### 類矩陣相乘法
* 假設$l_{ij}^{(m)}$代表i到j頂多經過m條邊的shortest path,可定義以下遞迴式
$l_{ij}^{(0)}=\begin{cases}
0 \ \ if \ \ i=j\\
\infty \ \ if \ \ i\neq j
\end{cases}$
$l_{ij}^{(m)}=min_{1\le k\le n}\{l_{ik}^{(m-1)}+w_{kj}\}$
由於shortest path頂多具有$n-1$條邊,所以可以保證$\delta(i,j)=l_{ij}^{(n-1)}=l_{ij}^{(n)}=l_{ij}^{(n+1)}=\cdots$
此算法時間複雜度是$\Theta(n^4)$,也可以透過reqeated squaring來加速讓它達到$\Theta(n^3lgn)$
```c=
//W 是weight matrix
All_pairs_shortest_path(W){
n = W.rows;
L = W;
for m = 2:n-1
for i = 1:n
for j = 1:n
for k = 1:n
L[i][j] = min(L[i][j],L[i][k]+W[k][j]);
return L;
}
Speedup(W){
n = W.rows;
L=W;
m = 1;
while m<n-1
for i = 1:n
for j = 1:n
for k = 1:n
L[i][j] = min(L[i][j],L[i][k]+L[k][j]);
m = 2*m;
return L;
}
```
### Floyd-Warshall Algorithm
* 可以有負邊,不能有負環
* 定義$d_{ij}^{(k)}$為i到j的shortest path且經過的intermediate verteices為$\{v_0,\cdots,v_k\}$,可定義以下遞迴式
$d_{ij}^{(k)}=\begin{cases}
w_{ij} \ \ if \ \ k=0\\
min(d_{ij}^{(k-1)},d_{ik}^{(k-1)}+d_{kj}^{(k-1)}) \ \ if \ \ k\ge 1
\end{cases}$
時間複雜度會是$\Theta(n^3)$
如果$d_{ii}^{(n-1)}<0$代表有負環
同時可以計算出predecessor matrix $M$,定義如下
$M_{ij}^{(0)}=\begin{cases}
NIL \ \ if \ \ i=j \ \ or \ \ w_{ij}=\infty\\
i \ \ if \ \ i\neq j \ \ and \ \ w_{ij}<\infty
\end{cases}$
$M_{ij}^{(k)}=\begin{cases}
M_{ij}^{(k-1)}\\
M_{kj}^{(k-1)}
\end{cases}$
```c=
Floyd_warshall(W){
n = W.rows;
D = W;
M={NULL};//init predecessor matrix
for i = 1:n
for j = 1:n
if i!=j && W[i][j]<INF
M[i][j]=i;
for k = 1:n
for i = 1:n
for j = 1:n
if D[i][j] > D[i][k]+D[k][j]
D[i][j] = D[i][k]+D[k][j];
M[i][j] = M[k][j];
return D;
}
```
* 可以利用此算法的概念來計算transitive closure,transitive closure $G^*=(V,E^*)$,若$(i,j)\in E^*$代表在$G$中,可以從$i$到$j$,定義$t_{ij}^{(k)}$代表從i到j經過$v_0\cdots v_k$能否到達,可定義以下遞迴式
$t_{ij}^{(0)}=\begin{cases}
0 \ \ if \ \ i\neq j \ \ and \ \ (i,j)\notin E\\
1 \ \ if \ \ i=j \ \ or \ \ (i,j) \in E
\end{cases}$
$t_{ij}^{(k)}=t_{ij}^{(k-1)}\vee (t_{ik}^{(k-1)}\wedge t_{kj}^{(k-1)})$
時間複雜度是$\Theta(n^3)$
```c=
Transitive_Closure(G){
n = G.V.size;
int T[n][n]={0};//init a matrix whose elements are all zero
for i=1:n
for j=1:n
if(i==j || (i,j) in G.E)
T[i][j]=1;
for k = 1:n
for i = 1:n
for j = 1:n
T[i][j] = T[i][j] or (T[i][k] and T[k][j]);
return T;
}
```
* 邊數較少的時候這樣做沒效率,可以直接執行$|V|$次的BFS時間複雜度會是$O(|V|(|E|+|V|))$
### Johnson's Algorithm for sparse graphs
* 重點在reweighting,剛開始給入的圖可以有負邊,透過reweighting將邊全部轉為非負,再對每個點做一次Dijkstra algorithm
* reweighting function : $\hat{w}(u,v)=w(u,v)+h(u)-h(v)$
1. 對於任意shortest path p來說,$w(p)=\delta(v_0,v_k) \Leftrightarrow \hat{w}(p)=\hat{\delta}(v_0,v_k)$
<img src="https://i.imgur.com/DtCPeZj.png">
2. $G$使用w沒有負環 iff $G$使用$\hat{w}$沒有負環
<img src="https://i.imgur.com/XM7YWgp.png">
* 如何決定$h(v)$的數值? 並讓它可以把每個edge重新做成nonnegative edge?
新增一個點$s$在圖中,並且此$w(s,v)=0,\forall v\in V$,計算出$\delta(s,v),\forall v\in V$,並讓$h(v)=\delta(s,v)$,透過triangle inequality可以知道$\delta(s,v)\le \delta(s,u)+w(u,v)$,所以$w(u,v)+\delta(s,u)-\delta(s,v)\ge 0$,所以可以定義$\hat{w}(u,v)=w(u,v)+\delta(s,u)-\delta(s,v)$
* 時間複雜度是一次Bellmand-Ford加上$|V|$次的Dijkstra所以是$\Theta(|V|^2lg|V|+|V||E|)$
```c=
Johnson(G,w){
G.V += s;//加入多的vertex s
for i = 1:|G.V|
G.E += (s,G.V[i]);
w(s,G.V[i]) = 0; //s到任意點的weight為0
if Bellman_Ford(G,w,s) == false
return "Neg cycle exists"
h[1..n];
for each v in G.V
h[v]=v.key;
for each (u,v) in G.E
w(u,v) = w(u,v)+h[u]-h[v]; //reweightin,v.key為Bellman-Ford過程中計算出的
D[0..n][0..n];
for each u in G.V
Dijkstra(G,w,u);//計算每個single source的最短路徑
for each v in V
D[u][v] = v.key + h[v] - h[u];//這裡的v.key是Dijkstra計算出的以u為source的最短路徑,reweighting
return D;
}
```
## Maximum Flow
* 問題描述: 給定一個flow network,是一個directed graph,每個邊有capacity $c(u,v)\ge 0$,且不允許self-loop,除了起點之外每個點都至少有一邊連到它,所以$|E|\ge |V|-1$
有以下幾個規定
Capacity constraint $0\le f(u,v)\le c(u,v),\forall u,v \in V$
Flow conservation: $\sum_{v\in V}f(v,u)=\sum_{v\in V}f(u,v),\forall u\in V-\{s,t\}$
* **deal with antiparallel edge**: 圖中若$(u,v)\in E$則$(v,u)\notin E$,若給定的圖兩點之間存在$(u,v),(v,u)\in E$,則在u、v之間加入一個新的點x,使得$c(u,x)=c(x,v)=c(u,v)$,如此一來就能替換掉antiparallel的情況產生 (證明正確性)
* **Multiple sources and sinks**
若給定的s、t不只一對,而是同時很多s跟t,則可以在圖中加入super source s'、super sink t',使得$c(s',s_i)=\infty,c(t_i,t')=\infty$,並以(s',t')為source跟sink解此題 (證明)
### The Ford-Fulkerson method
* 稱為method而非algorithm,因為實作方式會導致時間複雜度不同
* **Residual networks**
除了本來給的圖,會建構一張residual network $G_f=(V_f,E_f)$,若$(u,v)\in E$則$(u,v),(v,u)\in E_f$,而每個邊個residual capacity定義如下
$c_f(u,v)=\begin{cases}
c(u,v)-f(u,v) \ \ if \ \ (u,v)\in E\\
f(v,u) \ \ if \ \ (v,u)\in E\\
0 \ \ otherwise
\end{cases}$
如果$(u,v)\in E$,則$c_f(u,v)$代表的是邊$(u,v)$在$G_f$當中還能增加的flow的量,$c_f(v,u)$則表示邊$(u,v)$目前已經有多少flow在上面,或者說能減去多少flow
所以$G_f=(V,E_f),E_f=\{(u,v)\in V\times V:c_f(u,v)>0\}$
從定義可以看出$|E_f|\le 2*|E|$
再定義$f'$,若$f$是$G$中的flow,則$f'$代表在$G_f$中對應的flow
可以定義augmentation of flow $f$ and $f'$,$f\uparrow f':V\times V\rightarrow R$
$(f\uparrow f')(u,v)=\begin{cases}
f(u,v)+f'(u,v)-f'(v,u) \ \ if \ \ (u,v)\in E\\
0
\end{cases}$
證明$(f\uparrow f')$為$G$中的flow,且$|f\uparrow f'|=|f|+|f'|$ (驗證capacity constraint和flow conservation)
* **augmenting paths**
a simple path from s to t in $G_f$
* **residual capacity** of a path p
$c_f(p)=min\{c_f(u,v):(u,v)\in p\}$
* **cuts of flow**
將vertex分為兩個集合S,T,$s\in S,t\in T$,net flow $f(S,T)=\sum_{u\in S} \sum_{v\in T} f(u,v)-\sum_{u\in S}\sum_{v\in T} f(v,u)$
capacity of the cut
$c(S,T)=\sum_{u\in S}\sum_{v\in T}c(u,v)$
* flow network $G$上的任意cut都滿足$f(S,T)=|f|$ (證明)
* 任何flow值都小於等於任何capacity of cuts (證明)
* 由以上定理可以知道,找maximum flow事實上就是在找minimum cut
因為任何cut的flow值都相同,且都小於任何cut的capacity,所以最大的flow會小於等於最小的cut capacity
如何證明$|f|=c(S,T)$ ?
* 以下三個敘述等價
1. $f$ is a maximum flow in $G$
2. The residual network $G_f$ contains no augmenting paths
3. $|f|=c(S,T)$ for some cut $(S,T)$ of $G$
```c=
Ford_Fulkerson(G,s,t){
for each edge (u,v) in G.E
(u,v).f=0;
while there exists a path p from s to t in Gf
residual_capacity = INF;
for each edge (u,v) in p
if c_f(u,v) < residual_capacity;
residual_capacity = c_f(u,v);
for each edge (u,v) in p
if (u,v) in G.E
(u,v).f = (u,v).f+residual_capacity;
else
(v,u).f = (v,u).f-residual_capacity;
}
```
* 時間複雜度取決於如何找到s到t的simple path
用BFS找: polynomial time
如果maximum flow = $|f^*|$,則時間複雜度會是$\Theta(E|f^*|)$
### Edmonds-Karp Algorithm
* 在ford-fulkerson method中,使用BFS來找augmenting path,每次都會找到最短的augmenting path,時間複雜度會是$\Theta(VE^2)$
### Maximum bipartite matching
* 雙分圖當中找到最大的matching cardinality
* 透過將原本的雙分圖$G$變成$G'=(V',E'),V'=V\bigcup \{s,t\}$,且每個邊的capacity設為1,再找到此圖的maximum flow,就會是maximum bipartite matching cardinality
## 尤拉迴路及漢米爾頓環路
| 名稱 | 定義 | 備註 |
| -------- | -------- | -------- |
| Euler circuit | 存在一個circuit經過$G$中每一個邊恰好一次 | |
| Euler trail | 存在一個trail經過$G$中每個邊恰好一次 ||
| Hamiltonian cycle | 存在一個cycle經過$G$中每個點恰好一次 ||
| Hamiltonian path | 存在一個path經過$G$中每個點恰好一次 ||
* $G$具有euler circuit $\Leftrightarrow$ $G$為連通圖且$\forall v\in V,deg(v)$為偶數
$K_n$具有euler circuit $\Leftrightarrow$ $n$為奇數
$K_{m,n}$具有euler circuit $\Leftrightarrow$ $m,n$皆為偶數
如果$G$為有向圖
$G$具有euler circuit $\Leftrightarrow$ $G$為強連通圖且$\forall v\in V,id(v)=od(v)$
* $G$具有euler trail $\Leftrightarrow$ $G$為連通圖且$G$中洽含0個或2個點的度數為奇數,其餘皆為偶數 (含奇數的那兩個點會是起點與終點)
* 以下三點為Hamiltonian cycle的必要條件,可用來否定一個graph是否具有Hamiltonian cycle
1. $\forall v\in V,deg(v)\ge 2$
2. 若$\exists v\in V,deg(v)=2$,則與$v$相鄰的兩邊必在Hamiltonian cycle中
3. 若$\exists v\in V,deg(v)\ge 2$,且知道$v$相鄰的某兩邊在Hamiltonian cycle中,則與$v$相鄰的其他邊必不在此cycle中
* $Q_n,n\ge 2$必具有Hamiltonian cycle (證明)
有向完全圖$K_n^*$必具有有向的Hamiltonian path
* $G=(V,E),|V|\ge 3$為一個無迴圈的無向圖,若$deg(x)+deg(y)\ge n-1,\forall x,y\in V,x\neq y$,則$G$具有Hamiltonian path
若$\forall v\in V,deg(v)\ge (n-1/2$,則$G$具有Hamiltonian path
* $G=(V,E),|V|\ge 3$為一個無迴圈的無向圖,若$deg(x)+deg(y)\ge n,\forall x,y\in V,x,y$不相鄰,則$G$具有Hamiltonian cycle
若$\forall v\in V,deg(v)\ge n/2$,則$G$具有Hamiltonian cycle
* $K_n,n\ge 3$必有Hamiltonian cycle
$G=(V_1\bigcup V_2,E)$為一個連通的雙分圖
1. 若$G$具有Hamiltonian cycle,則$|V_1|=|V_2|$
2. 若$G$具有Hamiltonian path,則$||V_1|-|V_2||\le 1$
## 平面圖
* 若G可以被重畫之後,每個邊都不產生交叉,則稱為平面圖
* **基本區分elementary subdivision**
$G=(V,E),E\neq \emptyset$為一個無迴圈的無向圖,若去掉$e=\{x,y\}\in E$並加入$\{x,z\},\{z,y\},z\notin V$,這動作稱為$G$的一個基本區分
* **同胚homeomorphic**
$G_1,G_2$為兩個無迴圈的無向圖,以下狀況稱這兩個圖同胚
1. $G_1\cong G_2$
2. 經由某圖$H$經過數次基本區分後皆可得到$G_1,G_2$
* **Kuratowski's theorem**
$G$為平面圖 $\Leftrightarrow$ $G$不含子圖與$K_5,K_{3,3}$同胚
* 平面圖可將平面分割成多個區域(region, face),一個區域的度數為此區域邊界的邊數,所有區域的度數和洽為此圖邊數的兩倍
* $G=(V,E)$為一個平面圖且含$M$個分量圖,$r$表示區域個數,則$v-e+r=1+M$
* **Euler formula**
$G=(V,E)$為一個連通平面圖,$r$表示區域的個數,$v-e+r=2$
* $G=(V,E)$為一個無迴圈的簡單連通平面圖(樹),$|V|=v,|E|=e\ge 2,r$為區域個數
1. $3r/2\le e\le 3v-6$,因為每個區域的度數至少為三,若$e\ge 3v-6$可以否定它為平面圖
2. 若$G$不含任何三角形,則$e\le 2v-4$,因為每個區域的度數至少為四
若此圖中每個環路至少由k個邊組成(每個區域的度數至少k),$k\ge 3$,則$e\le (\cfrac{k}{k-2})(v-2)$ (證明)
## 著色問題
* 若$\forall (u,v)\in E,u,v$著不同顏色,則稱為$G$的一種正當著色
* $G$可以用n種顏色做正當著色,稱為n-colorable
可以使$G$為正當著色的最小n稱為$G$的chromatic number,$\chi(G)$,且稱$G$為n-chromatic
* 若$G$為n-colorable,則也會是(n+1)-colorable
$\chi(K_n)=n$
若$K_n$為$G$的子圖,則$\chi(G)\ge n$
$\chi(K_{m,n})=2$ (又一個判斷雙分圖的方式)
若$G$有k個分量圖,$\chi(G)=max_{1\le i\le k}(\chi(G_i))$
* 任意平面圖皆為4-colorable
* **著色多項式chromatic polynomial**
$P(G,\lambda)$表示最多使用$\lambda$種顏色對$G$做正當著色的不同方法數
$\chi(G)=min\{\lambda | P(G,\lambda)>0\}$
* 重要圖的著色多項式
1. $P(P_n,\lambda)=\lambda(\lambda-1)^{n-1}$
2. $P(K_n,\lambda)=P_n^{\lambda}=\lambda^{(n)}$
3. 有k個分量圖,$P(G,\lambda)=P(G_1,\lambda)\cdots P(G_k,\lambda)$
* **分解定理**
$G-e$表示把e={a,b}給移除,$G\cdot e$表示把$G-e$中的a,b給黏合
$P(G,\lambda)=P(G-e,\lambda)-P(G\cdot e,\lambda)$ (證明)
也可以表示成$P(G,\lambda)=P(G+e,\lambda)+P(G\cdot e,\lambda)$
* 若$G=(V,E),G_1=(V_1,E_1),G_2=(V_2,E_2),G=G_1\bigcup G_2,G_1\bigcap G_2=K_n$,則$P(G,\lambda)=\cfrac{P(G_1,\lambda)P(G_2,\lambda)}{\lambda^{(n)}}$
* $P(G,\lambda)$的常數項必定為0($P(G,0)=0$),係數和也必定為0($P(G,1)=0$)
* $|V|=n$則$P(G,\lambda)$為$\lambda$的n次多項式且$\lambda^n$的係數必定為1
## 樹
| 名稱 | 定義 | 備註 |
| -------- | -------- | -------- |
| 森林 | acyclic graph,無向無環圖 | |
| 樹 | acyclic connected graph | 樹必為森林,森林未必為樹 |
| degenerate tree | 退化樹,只含一個點的樹 ||
| 有向樹 | $G$為有向圖,將其視為無向圖時為一顆樹 ||
| 有根樹 | 有向樹中存在唯一一點$r,id(r)=0$ ||
| leaf | 有根樹中的$v\in V,od(v)=0$ ||
| internal node | 有根樹中的$v\in V,od(v)\neq0$ ||
| m-ary tree | 有根樹每個內部節點至多m個兒子 ||
| full m-ary tre | 有根樹每個內部節點恰好m個兒子 ||
* 樹不含環路,所以不含奇數長度的環路,所以樹為雙分圖,所以樹必為2著色圖
樹為邊數最少的連通圖
* $G$為無迴圈的簡單無向圖,下列為等價
1. $G$為樹
2. $G$中不含環路且$|E|=|V|-1$
3. $G$為連通圖且$|E|=|V|-1$
* $G$為非退化樹,$|V|\ge 2$,以下條件為等價
1. 任兩點恰有唯一路徑兩連
2. 去掉任一邊變為unconnected graph
3. 加入任一個$\{x,y\}\notin E$,會使$G$產生一個環路且該新增的邊一定在環路中
* $T=(V,E)$為一個非退化樹,則$T$中至少含兩個懸吊點 (證明)
* $T=(V,E)$為一顆m-ary tree,$|V|=n,i,l$分別代表內部節點及樹葉的個數
1. $n\le mi+1$
2. $l\le (m-1)+1$
3. $i\ge \cfrac{l-1}{m-1}$ 且 $i\ge \cfrac{n-1}{m}$