Đồ thị (Graph 2)

Lê Sỹ Vinh Bộ môn Khoa Học Máy Tính – Khoa CNTT Đại Học Công Nghệ - ĐHQGHN Email: vinhbio@gmail.com

Đồ thị (graph)

• G = (V, E)

– V: Tập đỉnh – E = { (u,v) | u, v ∈ V}: Tập cạnh

Ví dụ: Biểu diễn bản đồ đường đi trong thành phố bằng đồ thị G = (V, E)

– V: Tập hợp các điểm trong thành phố – E: Tập hợp các đường đi trong thành phố, mỗi đường đi nối hai điểm

Đi qua đồ thị theo chiều rộng (Breadth first search)

• Đi qua tất cả các đỉnh của đồ thị, mỗi đỉnh đúng một lần

• Bắt đầu xuất phát từ một đỉnh s, lần lượt thăm các đỉnh liền kề với s. Tiếp tục quá trình thăm các đỉnh theo nguyên tắc: Đỉnh nào được thăm trước thì các đỉnh liền kề với đỉnh đó sẽ được thăm trước

• Xem ví dụ

http://www.cs.princeton.edu/~wayne/cs423/lectures.html

Đi qua đồ thị theo chiều sâu (Depth first search)

//Đi qua đồ thị theo chiều sâu xuất phát từ v DepthFirstSearch (v) {

for (mỗi đỉnh u kề với v)

if (u chưa được thăm) {

thăm u và đánh dấu u đã được thăm DepthFirstSearch (u)

}

}

Xem ví dụ

http://www.cs.princeton.edu/~wayne/cs423/lectures.html

Sắp xếp topo

Cho đồ thị có hướng nhưng không có chu trình G = (V, E)

(Directed acylic graph / DAG)

Sắp xếp các đỉnh của đồ thị G thành một danh sách sao cho nếu có cung (u,v) ∈ E, thì đỉnh uuuuphải đứng trước đỉnh vvvv.

G A B C F E D

Sắp xếp topo

TopoSort (u) {

for (mỗi đỉnh v kề u)

if ( v chưa thăm)

TopoSort(v);

Xen u vào đầu danh sách T; Đánh dấu u đã thăm;

}

//Sắp xếp các đỉnh của đồ thị định hướng //không có chu trình G =(V,E) thành danh sách topo. TopoSortGraph(G) {

for (mỗi đỉnh u ∈ V)

Đánh dấu u chưa được thăm;

Khởi tạo danh sách topo T rỗng; for (mỗi đỉnh u ∈ V) if (u chưa thăm)

TopoSort (u);

}

Đường đi giữa hai điểm

Cho đồ thị G = (V, E)

Giữa hai đỉnh (x0, xk) có đường đi, nếu tồn tại (x1,…,xk-1 ) thỏa mãn

(xi, xi+1) ∈ E, ∀i = 0…(k-1)

Đồ thị liên thông (Connected graph)

Cho đồ thị G = (V, E), G được gọi là liên thông nếu tồn tại đường đi giữa hai

đỉnh bất kì của đồ thị

Tìm tất cả các thành phần liên thông

Cho đồ thị G = (V, E), tìm tất cả các thành phần liên thông của đồ thị. Đỉnh i

của đồ thị được gán nhãn ci cho biết thuộc miền liên thông ci.

Tìm các thành phần liên thông

//Đi qua đồ thị theo bề rộng xuất phát từ v FindConnectedComponent (v, ci) {

(1) Khởi tạo hàng đợi Q rỗng; (2) Xen v vào hàng đợi Q;

(3) Đánh dấu đỉnh v đã được thăm, và gán nhãn v bằng ci (4) while (hàng đợi Q không rỗng) { (5) Lấy đỉnh w ở đầu hàng đợi Q; for (mỗi đỉnh u kề w) (6) (7) if ( u chưa được thăm) { (8) (9)

Xen u vào đuôi hàng đợi Q; Đánh dấu u đã được thăm, và gán nhãn u bằng ci

}

(10)

Loại w ra khỏi hàng đợi Q

} // hết vòng lặp while.

}

Tìm các thành phần liên thông

for (mỗi v ∈V)

// Tìm các thành phần liên thông của đồ thị G=(V, E) FindAllConnectedComponent (G) { (10) (11) Đánh dấu v chưa được thăm; (12) ci = 0; (13) for (mỗi v ∈V) (14) if (v chưa được thăm) { (15) FindConnectedComponent(v, ci); (16) ci = ci + 1

}

}

Đường đi ngắn nhất

Cho đồ thị G=(V, E), cạnh (u, v) ∈ E có độ dài weight (u,v) > 0. Tìm đường

đi ngắn nhất từ đỉnh s đến đỉnh e

Tư tưởng thuật toán Dijkstra (thuật toán gán nhãn)

dist[v] = Khoảng cách đường đi ngắn nhất từ s đến v pre[v] = u: Đỉnh liền phía trước trên đường đi ngắn nhất từ s đến v

Gán nhãn (sửa nhãn):

Nếu

dist[u] + weight (u, v) < dist [v]

thì

dist [v] = dist[u] + weight (u, v) pre[v] = u

s → … → u → v

Thuật toán Dijkstra

Known = {tập hợp các đỉnh đã xác định được đường đi ngắn nhất từ s đến} Unknown = {tập hợp các đỉnh chưa xác định được đường đi ngắn nhất từ s đến}

Tiến hành quá trình lặp, tại bước i tìm đỉnh u ∈ unknown có khoảng cách nhỏ nhất.

if u = e then

kết thúc

else {

known = known ∪ {u} unknown = unknown – {u} Dùng u để sửa nhãn cho các đỉnh thuộc tập unknown tiến hành bước thứ (i + 1)

}

Dijkstra Algorithm {

Known = {s}; Unknown = {E} – {s} for v ∈ unknown {

dist[v] = weight [s, v]; pre[v] = s;

} u = s; // at the first step while (u != e ){

chọn u sao cho dist[u] = min {dist[x] | x ∈ unknown} Known = Known ∪ {u} Unknown = Unknown – {u} for v ∈ Unknown

if dist[u] + weight [u, v] < dist[v] {

//sửa nhãn cho v từ u dist[v] = dist[u] + weight[u,v]; pre[v] = u;

}

} path = {e} while (e != s) {

e = pre[e] path = {e} ∪ path

}

}