演算法 與 資料結構 Algorithm and Data Structure
- Graph Algorithm 圖論演算法
Graph Algorithm,圖?
大概是這麼回事:處理一些問題時,我們可以把問題想像成一個圖,而圖則是由點(node)
和邊(edge)所構成的。對於一個給定的圖,我們要如何對他做一些特定 性質的分析、如何利用這個圖的性質來解決相關問題、得到我們所需的資料 這些就是圖論演算法。
Definition 定義
圖Graph:一個圖可以用G = (V,E)來表示,其中V是頂點集合,E是邊集,
相鄰Adjacent:無向圖中,兩個點v和u相鄰當且僅當v和u之間存在一條邊。
有向圖中,一般若存在一條邊(u,v),則稱v和u相鄰(adjacent to u)。
度數Degree, Deg(v):無向圖中,指和Deg(v)指得是和v相鄰的頂點數。
若是有向圖則可進一步分為in-degree和out-degree,意義分別為連進v 的邊數(u→v),和連出v的邊數(v→u)。
路徑:由某個點v出發經過一系列的點而到達另外一個點u的走法。
有向圖Directed Graph:每條邊是單方向的,即一條邊(u,v)只代表能從u到v。
無向圖Undirected Graph:邊是雙向的,一條邊(u,v)代表u可以到v,v亦可到u。
權重圖Weighted Graph:每條邊有「權重」,代表這個邊所具有的數值,例如邊長。
連通圖Connected Graph:每對點之間都存在一條路徑可以相通。通常用於無向圖。
完全圖Complete Graph:任兩個點之間都有邊相連的圖。
圈Cycle:自一個點出發,可以不重複經過任何一個點而回到自己的路徑。
不含圈的圖Acyclic Graph:沒有cycle的圖。
簡單圖:不存在連接同一個點的邊(self-loop),且任兩點之間最多只有一條邊(無multi- edge)。
樹Tree:Connected acyclic graph。
Data Structures for Graph 圖的資料結構
一般來講,我們會給各個點編號,例如由0到n-1。
而邊的存法,最常見的為以下兩種:
Adjacency List相鄰串列:對於每個點,存下與它相鄰的所有頂點編號。
Adjacency Matrix相鄰矩陣:元素ADJ[v][u]代表v是否有邊到u。
兩者各有各的方便。Adjacency Matrix可以很快速的得知兩個頂點v和u間是否有邊相連,且 撰寫十分方便。Adjacency List在面對稀疏圖Sparse Graph(邊相對少)的圖時,在所需佔用 的空間、以及進行DFS時的時間,都比用Adjacency Matrix好很多(例如進行DFS時,用 Adjacency Matrix的時間複雜度是O(V2),用Adjacency List則是O(E))。
除此以外,亦有用Edge list等等其他資料結構,應視需要採用。
建中資訊培訓講義 (三) - by kelvin
Blind Search 盲目搜索
所謂盲目搜索,亦即對於題目沒有什麼輔助性、可供利用的結論,因此進行沒有特定策略
(Non-Heuristic)、全盤性的搜索。
BFS (Breadth-First Search) 廣度優先搜索
想法:由某個點s出發,同時拜訪(visit)所有相鄰的點,因此和s的最短距離相等的點會 在同一時期拜訪到。
實現:利用Queue來實現。
程序:
BFS (Visited, s) 1 for i ← 1 to n 2 do Visited[i] ← 0 3 Initialize Queue 4 Push(s)
5 Visited[s] ← 1
6 while Queue is not empty 7 do v ← Pop()
8 for u ← all vertices adjacent to v 9 do if Visited[u] = 0 10 do Push(u)
11 Visited[u] ← 1
DFS (Depth-First Search) 深度優先搜索
想法:由某個點s出發,到某個點v時,先任意挑一條邊繼續搜索,直到前進到某個點後若 其相鄰的點都已經被拜訪過,則回到上一個點繼續對別的邊進行拜訪。
實現:利用Stack實現。其實recursion就是一種stack。
程序:
DFS (Visited, v) // 開始時Visited[1~n]皆為0 1 Visited[v] ← 1
2 for u ← all vertices adjacent to v 3 do if Visited[u] = 0
4 do DFS(Visited, u)
DFS-ID (Iterative Deepening Depth-First Search) 漸深深度優先搜索
想法:BFS的缺點在於其佔用的空間很大;但需要進行廣度搜索時,DFS又不管用。但我們
可以使用DFS-ID。假設在所有狀態中,我們要求的是狀態S的深度,這時我們可以設
定一個「限制深度」d,使得每次DFS時搜索深度不超過d。我們讓d由1開始遞增,直 到我們可以找到狀態S為止。這個可以找到狀態S的d是最小可能的d,因此d其實就
建中資訊培訓講義 (三) - by kelvin
是我們要找的最小深度。
實現:直接對DFS稍作修改即可。
應用:在很多無法使用BFS的狀況可以省去不少時間。
Time-Stamp 時間戳記
利用DFS遍歷一個圖時,對於每個點可以紀錄他進入以及離開DFS function的時間(可以把 每個點進入、離開視作一連串的事件,時間由1開始到2n)。
這些資料可以用來解決一些相關問題。
Topological Sort 拓樸排序
對於數列我們可以進行sort,對於圖我們也可以!對於一個Directed Acyclic Graph G,我們 可以把點排序,使得當u可以到達v,u一定被排在v前面。
做法:用DFS遍歷所有的點,並紀錄其離開DFS function的時間t。對這些點依照他們的ti由 後到前排序,得到的順序即為所求。
題目一 – 塗雙色 (ACM 10004, Bicoloring)
給定一個Undirected Simple Graph,請回答是否存在一種方法,把每個點塗成黑色或白色,
且相鄰的點顏色必須不同?
題目二 – 3D迷宮 (ACM 532, Dungeon Master)
給你一個立體的格點迷宮,某些格子會是障礙物,無法通過。給定起點和終點,試問從起點 到終點最短的路徑為何?
題目三 – 字詞變換 (ACM 429, Word Transformation)
有一串詞彙代表所有的合法字串。對於一個字串S,每一次「變換」可以改變S中的其中一個 字,且不能改變它的長度,而且改變後得到的S’必須也是合法詞彙。給定兩個在合法字串中 的字串,試問至少要做幾次變換才能把其中一者變為另一者?
題目四 - Ancestor? Descendants? Siblings? Not Related?
給定一棵有root的tree的資料,可以使用O(n)的時間預處理。接下來會有很多個詢問,每個 詢問都需要在O(1)時間內達出。詢問包含兩個頂點u、v,對於每個詢問你要回答u、v之間的 關係是下列何者:
Ancestor祖先:u是v的祖先,亦即v在u的子樹中。
Descendants子代:u是v的子代,亦即u在v的子樹中。
Siblings兄弟:u和v是兄弟,亦即兩者的predecessor相同。
Not Related沒關係:不是以上三者。
題目五 - 跳格子遊戲 (NPSC 2006初賽, 題目A )
建中資訊培訓講義 (三) - by kelvin
給你一個沒有迴圈的有向圖Directed Acyclic Graph,兩位玩家輪流由起點各走一步,走到終 點的人贏。如果兩人每一步都是選擇對自己最有利的路徑,請問你最後是誰獲勝?
唔……
圖論本身就有非常非常多相關的問題,今天教的東西算是很基本的,希望大家都能弄熟。尤
其是BFS, DFS北市賽就可能遇到,千萬要寫熟啊!
[完]
建中資訊培訓講義 (三) - by kelvin