• Tidak ada hasil yang ditemukan

D Ç 圖論

N/A
N/A
Protected

Academic year: 2023

Membagikan "D Ç 圖論"

Copied!
7
0
0

Teks penuh

(1)

圖論

概述:

顧名思義,研究一堆奇奇怪怪的圖的性質。

定義:

(Graph):與一般的圖不同,在圖論中我們通常只考慮點點和點與之間的連結關 係,因此一張圖常用 , 。其中 V 代表點的集合,而 E 代表邊的集合。

(頂點,Vertex,Node):就是點點。

無向邊(邊,Edge):用來表示兩個點是有關係的。通常以 , 表示。注意邊是無 向的,即 , , 。而兩個點間可能不只一條邊,自己也可能連一條邊 到自己。

有向邊(弧,Arc):通常以 , 表示,而這個關係是有向的,即

, ,

相鄰(Adjacent):兩個點相鄰若且為若他們之間存在一條邊或一條弧連接。

有向圖(Directed Graph):連接關係皆為有向邊的圖。

無向圖(Undirected Graph):連接關係皆為無向邊的圖。

混合圖(Mix Graph):有向邊和無向邊混搭的圖。

途徑(Walk):一個邊點交錯形成的序列 , , , , … , , 。 其中 , ,

路徑(簡單路,Path):點和邊皆無重複的途徑。

(Trail):邊無重複的途徑。

(Cycle):起點與終點相同的途徑。

簡單環(Simple Cycle):點與邊無重複的途徑。

簡單圖(Simple Graph):無重邊和自環的圖。

連通圖(Cycle):任何點都有路徑相連的圖。

二分圖(Cycle):可以把圖上的所有點分在兩個 不相交的集合 A,B 使得集合內的點皆不相鄰。

(2)

有向無環圖(Directed Acyclic Graph):沒有環的有向圖。

(Tree):沒有環的連通圖。

分支度(Degree):和點 v 有關係的邊的數量,記作deg 。

入度(In-Degree):有向圖中終點為該點的邊的數量,記作deg出度(Out-Degree):有向圖中起點為該點的邊的數,記作deg 。

子圖(Sub-Graph):若兩個圖 , , = , ,則稱 的一個子圖。

生成子圖(Spanning Sub-Graph):一個 的子圖 且包含 的所有頂點。

生成樹(Spanning Tree):一個樹 為 的子圖且包含 的所有頂點。

圖的儲存

接下來要考慮的是如何儲存一張圖的資料,當然不可能開個小畫家之類用畫的。一般 常見的方法有相鄰矩陣相鄰串列還有前向星

相鄰矩陣:開一個 V*V 的二維陣列 adj[V][V]。邊 e(v1,v2)的資料就存在 adj[V][V]

優點:實作方便,修改方便,操作簡單……等潮爽得~

缺點:無法處理重邊,記憶體爆掉 ,操作複雜度不佳……等潮不爽得~

相鄰串列:開 V 條串列(或不定大小的陣列)儲存記錄一個點連接出去的所有邊。

優點:只需要 + 的記憶體,可處理重邊,操作複雜度好。

缺點:較不易實作,查詢一特定邊可能要

前向星:開一個陣列把所有邊存下來,並按照起點(若相等在按照終點)排序,且再 開一個數值陣列紀錄每一個點連出去的邊紀錄在哪個範圍的索引值。

優點:只需要 + 的記憶體,實作簡單,查一個特定的邊可以 lg 。 缺點:A_A。

1 2

5

3

4

1 2 3 4 5 1 0 1 1 0 0 2 0 0 0 2 1 3 0 0 0 0 1 4 0 0 0 0 0 5 1 0 1 0 0

1 1 2 2 2 3 5 5 5 2 3 4 4 5 5 1 2 3

[0,2,5,6,6,9]

[1] 2 3 [2] 4 4 5 [3] 5 [4] [5] 1 2 3

(3)

圖的遍歷

顧名思義,就是依某種順序拜訪過圖內的所有點。常見的有 DFS,BFS。

圖經過遍歷後走過的邊通常會形成一棵生成樹 or 森林。我們可以把邊分成四類。

Tree Edge:生成樹上的邊。

Back Edge:連向自己子孫非生成樹上的邊。

Forward Edge:連向祖先非生成樹上的邊。

Cross Edge:不屬於以上 3 種的邊。

深度優先搜索(DFS,Depth-First Search)

深度優先搜索會先搜尋一個點的子節點而非兄弟節點。一般會用遞迴實作,但如果 judge 開的遞迴 stack 大小不夠可能要考慮 overflow 的問題而自己開 stack 模擬。包 括後面所介紹用遞迴實作的演算法大部分都可以用 stack 模擬(可能有點痛苦就是)。

以下是用 stack 實作的代碼:

時間戳記

概念很簡單,就是在每一點戳上數字表示進入/離開的時間,一邊 DFS 一邊戳就可以 了。

Function DFS(bool visited[], vertex start, stack st) {

visited[] ← false st.push(start)

while(not st.empty()) Nowst.top() st.pop()

if(not visited[Now]) visited[Now] ← true

Foreach Vertex v adjecant to Now if(not visited[v])

st.push(v) }

1 2

5

3 4

6

進入順序:[1,2,3,4,5,6]

離開順序:[2,5,6,4,3,1]

(4)

拓樸排序(Topological Sort)

給一張有向圖,拓樸排序就是希望能找到一個拜訪點的順序,讓一個點被拜訪時所有 有弧指向它的點都已被拜訪過。簡單的來說就是你有一堆事情要做,但做一件事情前 可能必須先做完某些事情,而即是要求一種做事情的順序。

注意到有環的圖是不可能存在這種順序,故必須要是一個有向無環圖才可以。另外,

拓譜排序也不唯一。

考慮一下 DFS 離開點的時間戳記,可知對於兩個點 , ,若 時間戳記大於

1 是 子孫,(2) 與 在不同子樹上 兩者其中一個成立,故以離開點的時間戳記 倒轉變是一個合法的拓樸排序,時間複雜度為 + 。以下附上虛擬碼。

強連通元件(SCC,Strong Connected Component)

若一個圖是強連通的,它滿足在圖裡的任兩點 , 一定存在 兩條路 徑。現在給定一個有向圖,我們希望能把這個圖分成許多有強連通性質子圖,我們稱 它為強連通元件,而且還希望元件是最大的(即加入任意數量的任意其他點皆會破壞強

int Time

Function Topological_Sort(graph G, bool visited[], vertex Stamp[]) {

Time ← 0

visited[] ← false

Foreach Vertex Start G if(not visited[Start])

DFS(visited, Start, Stamp) }

Function DFS(bool visited[], vertex Now, vertex Stamp[]) {

visited[Now] ← true

Foreach Vertex v adjecant to Now if(not visited[v])

DFS(visited, v, Stamp) Stamp[Time] ←Now

Time Time + 1 }

(5)

連通性質。)對於這種問題,常見有兩種算法,Kosaraju’s 和 Tarjan’s。

Kosaraju’s:

對原圖做離開點的時間戳記,接者把圖上的邊都反過來,從時間戳記的相反順 序開始 DFS,可以走到的點都屬於同一個 SCC。時間複雜度為 +

Tarjan’s:

雖然 Tarjan’s 的時間複雜度也為 + ,但在實作上據說 Tarjan 因為不需 要建構反向圖等所以常數會比 Kosaraju 小許多,再者 Tarjan 的 SCC 算法與後面 的 BCC 等概念相似,因此介紹 Tarjan。首先要定義點的 Dfn 與 Low 值:

Dfn(v):點 v 在 DFS 中進入點的時間戳記。

Low(v):Min(Dfn[v], low[u], dfn[w])

其中 u 為 v 的所有子節點,w 為 v 經過 Back Edge 連到的點

可以知道 Low 值的意涵即為自己和自己子孫可以連回到的頂點鐘時間戳記值的最 小值,因此若某一點 有%&' ()* 則以 為頂點的 DFS 子樹屬於同一個強 連通元件。以下附上虛擬碼。

int Time ← 0, count ← 0 , stack st , list SCC

Function Tarjan(bool visited[], vertex Now, int Dfn[], int Low[]) {

visited[Now] ← true

Dfn[Now] ←Time , Low[Now] ←Time , TimeTime + 1 st.push(Now)

Foreach Vertex v adjecant to Now if(not visited[v])

Tarjan(visited, v, Dfn, Low)

Low[Now]=Min(Low[Now], Low[v]) Else if(v is in st)

Low[Now]=Min(Low[Now], Dfn[v]) if(Dfn[Now] = Low[Now])

Repeat

v st.top() , st.pop()

SCC[count] SCC[count] v Until (v = Now)

countcount + 1 }

(6)

縮點

把 SCC 都求出後可以構造一個新圖把 SCC 都縮成一個點, , , ,

存在若且為若存在 ,∈ , , ∈ , 。新的圖會是一個 DAG,這樣 通常就會有一些神祕的性質可用或是根本沒用。

雙連通元件(BCC,Bi-Connected Component)

先來一些定義:

(點/邊)雙連通:圖上至少要拔掉 2 個(點/邊)才能讓原圖斷成多個連通區塊。

割點(AP, Articulation Point):拔掉這一點就會讓一個連通圖變成多個互不連通的 子圖,就如同 CKAP掛了可能上課在打區網對戰的電腦就會斷線。

橋(Bridge) :拔掉這一條邊就會讓一個連通圖變成多個互不連通的子圖,就如同 打橋牌的時候斷橋了一樣悲劇。

(點/邊)雙連通元件:如同 SCC 一樣,我們希望把圖分成多個(點/邊)雙連通元件且 每個元件是最大的。注意到點雙連通元件可能有重疊的點。

而割點、橋和雙連通元件都可以用 Tarjan’s 來求,做法也一樣即在無向圖中計算 Low 值,只是要特別注意不能跟 DFS Tree 上的父節點做更新 Low 值的動作(除非有 Back Edge 連到)。虛擬碼基本上跟 SCC 差不多。

一個點 是割點若且為若( i ) 是樹根且他的子孫數 > 1 或( ii ) 不是樹根且對於 存在一個子節點.都有%&' ≤ ()* .

一個邊 , 是橋若且為若 在 DFS 樹為 Tree Edge 且%&' < ()*

點雙連通元件求法與 SCC 類似,碰到割點時就把點一個個從 stack 取出直到頂端 的點為割點為止,而取出的點與割點和之間的邊構成一點雙連通元件。

邊雙連通元件只要把橋從圖上刪去,每一個連通子圖就是一個邊雙連通元件。

(7)

題目(A_A)

跳格子遊戲 <NPSC2006 初賽(prob A)> [TIOJ 1092]

給你一個 DAG,兩人輪流從其點開始各走一步,問哪個人有必勝策略。 +

八卦傳播系統 <建中校內培訓第二次模擬考試> [TIOJ 1451]

給你一個有向圖,選最少個起點使得每個點都可由某個起點走到。 , ≤ 100000

ATM <APIO '09> [TIOJ 1744]

給你一個有向圖,每個點上都有 ATM,有些點上有酒吧,你計畫要從起點開始,

碰到 ATM 就可以搶錢(搶第二次不會有錢),最後趁著吃牢飯錢到一家酒吧慶祝,

問你最多能搶多少錢。 , ≤ 500000

Crayfish < Algorithmic Engagements (PA) 2006 Round 4 > [TIOJ 1686]

有一隻龍蝦要拜訪一些蝦龍(無誤),蝦龍的家和路構成一有向圖,龍蝦傲嬌的時候 會逆向而行,而有些特別的路當他是正常模式會讓他進入傲嬌模式,反之亦然。對 每個蝦龍的家輸出當起點時龍蝦可以回到原點的條件下拜訪到其他不同於起點的 蝦龍數目的最大值,龍蝦從蝦龍的家出發時是傲嬌的。 ≤ 10000, ≤ 100000

滿漢全席 <94 全國賽(prob 4)> [TIOJ 1149]

有 N 個食材,每種食材可選擇煮成滿氏或漢氏,有 M 位評審,每個評審都會希望 你做出 2 個特定的食材搭配滿/漢氏,問你能不能變成阿基師。 3 + 4

圓桌武士 < ACM-ICPC Central Europe 2005 prob A> [TIOJ 1684]

有 N 個武士之中有 M 組憎恨關係,他們可以選一些人在圓桌上開會,坐在圓桌上 的條件是(1)相鄰兩人都不互相憎恨(2)圓桌上坐奇數個人。問幾個武士完全沒機會 坐上圓桌。 4 ≤ 1000, ≤ 1000000

Referensi

Dokumen terkait

設有甲、乙兩支瓶子,開始時,甲瓶裝有a公升的水,乙瓶裝有b公升的水。每一輪操作 都是先將甲瓶水量的三分之一倒入乙瓶,然後再將乙瓶水量的三分之一倒回甲瓶。第一輪、 第二輪、第三輪、…不斷操作下去,求穩定狀態時,甲瓶中有 ○16 ○17 公升的水。 C... 右圖是將兩個邊長為1的正六邊形,共用一邊連接而成 的平面圖形,若A,B,C為其中三個頂點,則內積

將圖二的正四角錐ABCDE沿著其中的四個邊剪開後,形成的展開圖為圖三。 判斷下列哪一個選項中的四個邊可為此四個邊? AAC、AD、BC、DE BAB、BE、DE、CD CAC、BC、AE、DE DAC、AD、AE、BC 答案:A 解析: ○1 若甲為△ABC時, ○2 若甲為△ACD時, 則剪開的四個邊為AB、AC、BE、CD。