Luận văn Một số bài toán tối ưu trên đồ thị và ứng dụng

Lời cam đoan

Lời cảm ơn

Mục lục 1

Lời nói đầu 3

Danh sách bảng 5

Danh sách hình vẽ 6

1 KIẾN THỨC CHUẨN BỊ 7

1.1 CÁC KHÁI NIỆM CƠ BẢN VỀ ĐỒ THỊ . . . . . . . . . . . . . 7

1.1.1 Các định nghĩa và thí dụ . . . . . . . . . . . . . . . . . . . 7

1.1.2 Biểu diễn đồ thị . . . . . . . . . . . . . . . . . . . . . . . 11

1.2 ĐƯỜNG ĐI VÀ TÍNH LIÊN THÔNG . . . . . . . . . . . . . . 15

1.2.1 Đường đi và chu trình . . . . . . . . . . . . . . . . . . . . 15

1.2.2 Tính liên thông . . . . . . . . . . . . . . . . . . . . . . . . 17

2 BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT TRÊN ĐỒ THỊ 19

2.1 BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT . . . . . . . . . . . 20

2.2 THUẬT TOÁN DIJKSTRA . . . . . . . . . . . . . . . . . . . . 21

2.2.1 Mô tả thuật toán . . . . . . . . . . . . . . . . . . . . . . . 21

2.2.2 Chứng minh tính đúng đắn của thuật toán . . . . . . . . . . 23

2.2.3 Độ phức tạp của thuật toán . . . . . . . . . . . . . . . . . 27

pdf51 trang | Chia sẻ: honganh20 | Ngày: 05/03/2022 | Lượt xem: 253 | Lượt tải: 2download
Bạn đang xem trước 20 trang tài liệu Luận văn Một số bài toán tối ưu trên đồ thị và ứng dụng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
đi từ một đỉnh đầu tới một đỉnh cuối. Nếu với hai đỉnh u, v bất kỳ, có nhiều nhất một cạnh đi từ u tới v thì G được gọi là một đồ thị đơn có hướng. Nếu (a, b) ∈ E thì (a, b) được gọi là cạnh (cung) của G với đỉnh đầu là a, đỉnh cuối là b và có hướng đi từ a tới b. Ví dụ 1.1.1. a. Đồ thị vô hướng G = (V,E) trong đó: V = {a, b, c, d, e, f}, E = {(a, b), (a, e), (b, e), (c, d)} (Hình 1.1.a) b. Đồ thị có hướng G = (V,E) trong đó: V = {a, b, c, d, e, f}, E = {(a, b), (b, e), (c, d), (d, c), (e, a), (f, f)} (Hình 1.1b) Đồ thị G = (V,E) được gọi là đồ thị có trọng số (hay trọng đồ), nếu mỗi cạnh có một trọng số kết hợp, thường được cung cấp bởi một hàm trọng số w : E → R. Ví dụ 1.1.2. a. Đồ thị vô hướng G = (V,E) trong đó: V = {a, b, c, d, e, f}, E = {(a, b), (a, e), (b, e), (c, d)} 9(a) Đơn đồ thị vô hướng (b) Đơn đồ thị có hướng Hình 1.1: Đơn đồ thị vô hướng(a) và có hướng(b) và w(a, b) = 3, w(a, e) = 4, w(b, e) = 4.5, w(c, d) = 6 (Hình 1.2a) b. Đồ thị có hướng G = (V,E) trong đó: V = {a, b, c, d, e, f}, E = {(a, b), (b, e), (c, d), (d, c), (e, a), (f, f)} w(a, b) = 1.5, w(b, e) = 2, w(c, d) = 5,w(d, c) = 3.2, w(e, a) = 4, w(f, f) = 8 (Hình 1.2b) (a) (b) Hình 1.2: Đơn đồ thị vô hướng có trọng số(a) và có hướng có trọng số (b) Định nghĩa 1.1.3. Một đồ thị con của đồ thị G là một đồ thị H = (W,F ) sao choW ⊂ V, F ⊂ E. Tiếp sau đây là một số thuật ngữ cơ bản của lý thuyết đồ thị. 10 Trước tiên, ta xét các thuật ngữ mô tả các đỉnh và các cạnh của đồ thị vô hướng. Nếu (u, v) là một cạnh nằm trong đồ thị G = (V,E) ta nói đỉnh v kề với đỉnh u. Trong đồ thị vô hướng, quan hệ kề là đối xứng. Nếu e = (u, v) là cạnh của đồ thị ta nói cạnh này là liên thuộc với hai đỉnh u và v, hoặc cũng nói là nối đỉnh u và đỉnh v, đồng thời các đỉnh u và v sẽ được gọi là các đỉnh đầu của cạnh (u, v). Để biết có bao nhiêu cạnh liên thuộc với một đỉnh, ta dựa vào định nghĩa sau: Định nghĩa 1.1.4. Bậc của một đỉnh trong một đồ thị vô hướng là số lượng các cạnh liên thuộc trên nó. Ký hiệu: deg(v). Đỉnh v được gọi là đỉnh cô lập nếu deg(v) = 0. Đỉnh v được gọi là đỉnh treo nếu deg(v) = 1. Ta xét các thuật ngữ tương tự cho đồ thị có hướng Tương tự với đồ thị vô hướng, ta có khái niệm về quan hệ kề đối với đồ thị có hướng. Và trong một đồ thị có hướng, quan hệ kề không nhất thiết đối xứng. Nếu v kề với u trong một đồ thị có hướng, đôi lúc ta viết u→ v. Nếu (u, v) là một cạnh trong một đồ thị G = (V,E) , ta nói rằng (u, v) liên thuộc từ (incident from) đỉnh u và liên thuộc đến (incident to) đỉnh v. Định nghĩa 1.1.5. Trong một đồ thị có hướng, bậc đi ra của một đỉnh là số lượng cạnh rời khỏi nó, bậc đi vào của một đỉnh là số lượng cạnh nhập vào nó. Bậc của một đỉnh trong đồ thị có hướng là bậc đi ra cộng bậc đi vào của nó. Hay ta còn có thể viết dưới dạng sau: Giả sử G = (V,E) là một đồ thị có hướng và v ∈ V . Kí hiệu: 11 d+(v) = {x ∈ V |(v, x) ∈ E} d−(v) = {y ∈ V |(y, v) ∈ E} Khi đó |d+(v)| được gọi là bậc đi ra, |d−(v)| được gọi là bậc đi vào của v. d(v) = d+(v) + d−(v) Đỉnh v được gọi là đỉnh cô lập nếu d+(v) + d−(v) = 0. Đỉnh v được gọi là đỉnh treo nếu d+(v) + d−(v) = 1. 1.1.2 Biểu diễn đồ thị Biểu diễn đồ thị trên mặt phẳng là một biểu diễn cho ta phép nhìn nhận đối tượng này một cách khá trực quan. Tuy nhiên, ta vẫn cần tới các biểu diễn khác của đồ thị để đáp ứng các đòi hỏi khác nhau của các ứng dụng. Và có hai cách thường dùng để biểu diễn một đồ thị G = (V,E) : sử dụng một danh sách kề hoặc sử dụng một ma trận kề. Phép biểu diễn danh sách kề cung cấp một cách gắn gọn để biểu diễn các đồ thị thưa - là những đồ thị mà |E| nhỏ hơn nhiều so với |V |2. Phép biểu diễn ma trận kề được ưa dùng khi đồ thị là trù mật -|E| sát với |V |2 hoặc khi ta cần nhanh chóng biết một cạnh nối hai đỉnh đã cho hay không. Biểu diễn đồ thị bằng danh sách kề Trong khoa học máy tính, danh sách kề là một cấu trúc dữ liệu gắn bó chặt chẽ với việc biểu diễn đồ thị. Phép biểu diễn danh sách kề của một đồ thị G = (V,E) gồm một mảng Adj có độ lớn là |V |, ứng với các đỉnh của V . Với mỗi đỉnh u của đồ thị, ta cho tương ứng với nó một danh sách các đỉnh kề với u, nghĩa là sao cho có cạnh 12 (u, v) ∈ E. Nếu G là một đồ thị có hướng thì tổng các chiều dài của tất cả các danh sách kề là |E|, bởi mỗi cạnh (u, v) thể hiện v xuất hiện trong Adj[u]. Nếu G là một đồ thị vô hướng thì tổng các chiều dài của tất danh sách kề là 2|E|, vì nếu (u, v) là một cạnh vô hướng thì u xuất hiện trong danh sách kề của v và ngược lại. Danh sách kề có thể thay đổi để biểu diễn đồ thị có trọng số. Khi đó, trọng số w(u, v) của cạnh (u, v) được lưu trữ với đỉnh v trong danh sách kề của u. Một nhược điểm của phép biểu diễn danh sách kề đó là để xác định xem một cạnh đã cho (u, v) có tồn tại trong đồ thị hay không, ta không còn cách nào nhanh hơn là tìm kiếm v trong danh sách kề Adj[u].Có thể khắc phục nhược điểm này bằng một phép biểu diễn ma trận kề của đồ thị, để đổi lại, ta phải dùng nhiều bộ nhớ hơn. Ví dụ 1.1.3. Hai phép biểu diễn đồ thị vô hướng Hình 1.1a. (a) Biểu diễn danh sách kề của G (b) Biểu diễn ma trận kề của G Hình 1.3: Hai phép biểu diễn đồ thị vô hướng trong hình 1.1a Ví dụ 1.1.4. Hai phép biểu diễn của đồ thị có hướng Hình 1.1b 13 (a) Biểu diễn danh sách kề của G (b) Biểu diễn ma trận kề của G Hình 1.4: Hai phép biểu diễn đồ thị có hướng trong hình 1.1b Biểu diễn đồ thị bằng ma trận kề Xét đơn đồ thị vô hướng G = (V,E) với tập đỉnh V = {v1, v2, . . . , vn}. Khi đó ma trận kề của đồ thị G là ma trận A = (aij)n×n =  a11 a12 . . . a1n a21 a22 . . . a2n . . . an1 an2 . . . ann  trong đó: aij =  1, nếu (vi, vj) ∈ E 0, nếu (vi, vj) /∈ E 14 Dễ thấy rằng ma trận kề A của đồ thị có hướng G hoàn toàn xác định G. Vì vậy, ma trận kề được coi là một biểu diễn của G. Ta có một số tính chất: Tính chất 1.1.1. i. Ma trận kề của đồ thị vô hướng là một ma trận đối xứng. ii. Tổng các phần tử trên dòng i (cột j) bằng bậc của đỉnh tương ứng. Cũng tương tự phép biểu diễn danh sách kề của một đồ thị, phép biểu diễn ma trận kề có thể được dùng cho các đồ thị có trọng số. Khi đó, nếu G là một đồ thị có trọng số, ta có ma trận A = (aij)n×n trong đó: aij =  w(vi, vj), nếu (vi, vj) ∈ E 0, nếu (vi, vj) /∈ E Ví dụ 1.1.5. Ví dụ về danh sách kề và ma trận kề có trọng số cho đồ thị trong ví dụ 1.2a. (a) Biểu diễn danh sách kề của G (b) Biểu diễn ma trận kề của G Hình 1.5: Hai phép biểu diễn đồ thị có trọng số trong hình 1.2a 15 1.2 ĐƯỜNG ĐI VÀ TÍNH LIÊN THÔNG 1.2.1 Đường đi và chu trình Xét một đồ thị vô hướng Giả sử G = (V,E) là một đồ thị vô hướng. Một đường đi trong G là một dãy v0e1v1e2v2 . . . envn sao cho: + Với mọi i = 0, 1, 2, .., n, vi ∈ V , + Với mọi i = 1, 2, . . . , n, ei ∈ E và ei = (vi−1, vi) hoặc ei = (vi, vi−1). Khi đó, n được gọi là độ dài, đỉnh v0 được gọi là đỉnh đầu, đỉnh vn được gọi là đỉnh cuối của đường đi trên. Một chu trình là một đường có điểm đầu và điểm cuối trùng nhau. Một đường đi đơn (chu trình đơn) là một đường đi (chu trình) không đi qua cạnh nào quá một lần. Xét một đồ thị có hướng Hoàn toàn tương tự, ta có các định nghĩa với đồ thị có hướng. Giả sử G = (V,E) là một đồ thị có hướng. Một đường đi trong G là một dãy v0e1v1e2v2 . . . envn sao cho: + Với mọi i = 0, 1, 2, .., n, vi ∈ V , + Với mọi i = 1, 2, . . . , n, ei ∈ E và ei = (vi−1, vi). Khi đó n được gọi là độ dài, đỉnh v0 được gọi là đỉnh đầu, đỉnh vn được gọi là đỉnh cuối của đường có hướng trên. Một đường đi đơn (chu trình đơn) là một 16 đường đi (chu trình) không đi qua cạnh nào quá một lần. Trong trường hợp đồ thị có hướng, xét một đường đi v0e1v1e2v2 . . . envn, mỗi cạnh ei đều có đỉnh đầu là đỉnh đứng trước và đỉnh cuối là đỉnh đứng sau ei trong dãy, tức là nó được xác định bởi chính hai đỉnh đó. Vì vậy, khi đồ thị không có cạnh bội, ta biểu diễn đường đi bằng dãy các đỉnh, bỏ qua các cạnh, và đơn giản gọi dãy các đỉnh v0v1v2 . . . vn của G là đường đi trong G nếu với mọi i = 0, 1, ...., n− 1, (vi, vi+1) là một cạnh của G. Ví dụ 1.2.1. Giả sử G = (V,E) là đồ thị có hướng như hình 1.6. Khi đó: a. a→ b→ f → e→ b→ c là một đường đi có hướng với đỉnh đầu là a, đỉnh cuối là c với độ dài bằng 5. b. a→ b→ e→ d→ c→ b→ e→ f là một đường đi vô hướng với đỉnh đầu là a, đỉnh cuối là f với độ dài bằng 7. c. b→ f → e→ b là một đường đi có hướng khép kín. d. b→ e→ d→ c→ b là một đường đi vô hướng khép kín. Hình 1.6: Ví dụ về một đồ thị có hướng 17 1.2.2 Tính liên thông Xét một đồ thị vô hướng Định nghĩa 1.2.1. Một đồ thị G = (V,E) được gọi là liên thông nếu với hai đỉnh vivà vj khác nhau bất kỳ của G đều tồn tại một đường đi đơn trong G với đỉnh đầu là vi và đỉnh cuối là vj . Trong trường hợp ngược lại, đồ thị được gọi là không liên thông. Một thành phần liên thông của G là một đồ thị con liên thông cực đại (theo nghĩa bao hàm) của G. Ta có mệnh đề sau: Mệnh đề 1.2.1. Với mọi cặp đỉnh u, v khác nhau, các thành phần liên thông chứa u và chứa v hoặc trùng nhau, hoặc rời nhau. Chúng trùng nhau khi và chỉ khi u và v được nối với nhau bởi một đường đi. Xét một đồ thị có hướng Định nghĩa 1.2.2. Một đồ thị G = (V,E) được gọi là liên thông yếu (liên thông) nếu với hai đỉnh vi và vj khác nhau bất kỳ của G đều tồn tại một đường đi đơn trong G với đỉnh đầu là vi và đỉnh cuối là vj . Trong trường hợp ngược lại, đồ thị được gọi là không liên thông. Ngoài ra, ta có định nghĩa liên thông mạnh cho đồ thị có hướng. Định nghĩa 1.2.3. Một đồ thị G = (V,E) được gọi là liên thông mạnh nếu với hai đỉnh bất kỳ khác nhau vi và vj , tồn tại cả đường đi với đỉnh đầu là vi, đỉnh cuối là vj và đường đi với đỉnh đầu là vj , đỉnh cuối là vi. 18 Nhận xét 1.2.1. Một đồ thị liên thông mạnh thì liên thông. Điều ngược lại chưa chắc đúng. Như vậy hai máy tính bất kỳ trong mạng có thể trao đổi thông tin được với nhau khi và chỉ khi đồ thị tương ứng với mạng này là đồ thị liên thông. Ví dụ 1.2.2. Đồ thị trong hình 1.1a là đồ thị vô hướng không liên thông. 19 CHƯƠNG 2 BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT TRÊN ĐỒ THỊ Một trong số các bài toán quan trọng của lý thuyết đồ thị là bài toán tìm đường đi ngắn nhất giữa hai đỉnh trong một đồ thị. Trong thực tế, bài toán này có một ý nghĩa to lớn, vì nhiều bài toán có thể đưa về dạng bài toán tìm đường đi ngắn nhất. Ví dụ, bài toán chọn một hành trình tiết kiệm nhất (theo khoảng cách hoặc thời gian hoặc chi phí) trên một mạng giao thông đường bộ, đường thủy hoặc đường không, bài toán lập lịch thi công các công đoạn trong một công trình lớn, bài toán lựa chọn đường truyền tin với chi phí nhỏ nhất trong mạng thông tin,. . . Và để giải quyết những bài toán đó, các thuật toán được xây dựng dựa trên cơ sở lý thuyết đồ thị tỏ ra là các thuật toán có hiệu quả. Trong chương này chúng ta sẽ xét một số thuật toán như vậy. 20 2.1 BÀI TOÁN TÌM ĐƯỜNG ĐI NGẮN NHẤT Cho một đồ thị có hướng có trọng số G = (V,E,w). Độ dài một đường đi p = (v0v1...vk) được định nghĩa bởi: w(p) = ∑k 1 w(vi−1, vi) Ta định nghĩa khoảng cách đường đi ngắn nhất δ(u, v) từ u đến v bởi công thức: δ(u, v) =  minw(p), nếu có một lộ trình từ u đến v ∞, nếu không có một lộ trình từ u đến v Khi đó, một đường đi p từ u đến v là ngắn nhất nếu w(p) = δ(u, v). Ta có thể có các dạng của bài toán: 1. Cho trước 2 đỉnh. Tìm một đường đi ngắn nhất giữa chúng. 2. Cho trước 1 đỉnh. Tìm một đường đi ngắn nhất từ đỉnh đó đến các đỉnh còn lại. 3. Cho trước 1 đỉnh. Tìm một đường đi ngắn nhất từ mỗi đỉnh đến đỉnh đó. 4. Tìm một đường đi ngắn nhất giữa tất cả các cặp đỉnh. Ta dễ dàng nhận thấy, bài toán thứ hai và thứ ba là bài toán ngược của nhau, nên độ khó là tương đương. Bài toán thứ nhất là trường hợp con của bài toán thứ hai, và bài toán thứ hai là trường hợp con của bài toán thứ tư. Tuy nhiên, ta sẽ thấy rằng thực chất việc giải bài toán thứ nhất không đơn giản 21 hơn giải bài toán thứ hai, vì muốn tìm đường ngắn nhất giữa hai đỉnh, ta vẫn phải khảo sát cả đồ thị. Ngược lại, việc giải bài toán thứ hai lại thực sự đơn giản hơn bài toán thứ tư, và một trong những thuật toán có độ phức tạp thấp để giải bài toán thứ tư là gọi n lần bài toán thứ hai, mỗi lần chọn đỉnh nguồn là một đỉnh của đồ thị. 2.2 THUẬT TOÁN DIJKSTRA Thuật toán Dijkstra được mang tên nhà khoa học máy tính người Hà Lan Edsger Dijkstra vào năm 1956 và công bố năm 1959, là một thuật toán giải quyết bài toán đường đi ngắn nhất nguồn đơn trong một đồ thị có hướng liên thông không có cạnh mang trọng số âm. Dữ kiện của bài toán quy về việc xét bài toán thứ nhất. Trong phần này, ta sẽ tập trung vào mô tả thuật toán và chứng minh tính đúng đắn của thuật toán. Độ phức tạp sẽ thừa nhận, không chứng minh. 2.2.1 Mô tả thuật toán Thuật toán áp dụng cho các đồ thị liên thông có trọng số không âm. Trong thuật toán này, ở mỗi bước, ta đã xét thêm được một đỉnh v, xác định được đường đi ngắn nhất từ s đến v. Mục đích của việc cập nhật là để xét các đỉnh lân cận u với v xem đường đi mới từ s đến u và thông qua v có ngắn hơn đường đi cũ hay không, nếu ngắn hơn thì ta thay thế nó cho đường đi cũ, và v sẽ được gán cho p[u]. 22 Giả mã: Input: G = (V,E,w); s ∈ V Output:Một đường đi ngắn nhất từ s đến v SP (s, v);∀v ∈ V ; begin d[v]: độ dài đường đi ngắn nhất từ s đến v; p[v]: đỉnh trước v trong đường đi từ s đến v; S := ∅; Q := {s}; foreach {v ∈ V } do if {v = s} then d[v] := 0; else d[v] :=∞; p[v] := null; Q := Q ∪ {v} end end while {Q 6= ∅} do v := đỉnh trong Q sao cho d[v] nhỏ nhất for {u ∈ Adj(v) and u /∈ S} do if {d[u] > d[v] + d[v, u]} then d[u] := d[v] + d[v, u]; p[u] := v; if {u /∈ Q} then Q := Q ∪ {u}; end end end S := S ∪ {v}; Q := Q \ {v}; end end Algorithm 1: Thuật toán Dijkstra 23 2.2.2 Chứng minh tính đúng đắn của thuật toán Ta có nhận xét sau: Nếu tại thời điểm t, d[u] <∞ thì tồn tại một đường đi từ s đến u mà chỉ đi qua những đỉnh thuộc S. Trong quá trình chứng minh, ta kí kiệu thêm biến chỉ số thời gian, St, Qt, dt[v] là S,Q, d[v] tại thời điểm t. Gọi δ(v) là độ dài đường đi ngắn nhất từ s đến v trên đồ thị G. Để chứng minh thuật toán trên đúng đắn, ta sẽ chứng minh các điều sau: 1. Nếu v ∈ St thì dt[v] = δ(v). 2. Nếu u ∈ Qt thì dt(u) là độ dài đường đi ngắn nhất từ s đến u mà chỉ đi qua các đỉnh trong St. Chứng minh. Ta sẽ chứng minh bằng phương pháp quy nạp theo t ≥ 1. Giả sử ý 1 và ý 2 đúng đến thời điểm t− 1. Ta cần chứng minh ý 1 và ý 2 đúng tại thời điểm t. * Chứng minh 1 Giả sử v là điểm được thêm vào tại thời điểm t: St = St−1 ∪ {v} Giả sử có một đường đi p∗ từ s đến v sao cho w(p∗) < dt[v]. Hình 2.1: Minh họa cho chứng minh ý 1. 24 Vì dt[v] = dt−1[v] là độ dài đường đi ngắn nhất từ s đến v và chỉ đi qua các đỉnh thuộc St−1 (dựa vào tính chất 2 trong thời gian t− 1) nên p∗ chứa ít nhất 1 đỉnh nằm ngoài St−1. Gọi z là đỉnh đầu tiên như thế trên p (tính từ s). Gọi p1 là một đường đi từ s đến z chỉ đi qua các đỉnh thuộc St−1, p2 là một đường đi từ z đến v. Khi đó: w(p∗) = w(p1) + w(p2) > w(p1) ≥ dt−1[z] (Vì p1 là đường đi từ s đến z chỉ đi qua các đỉnh thuộc St−1 nên w(p1) ≥ d[z].) Mặt khác, w(p∗) < dt[v] = dt−1[v]. Suy ra dt−1[v] > dt−1[z], mâu thuẫn với cách chọn v. Vậy điều giả sử là sai, hay dt[v] = δ(v). * Chứng minh 2 Ta có, dt[u] = min{dt−1[u], dt[v] + d[v, u]}, với u ∈ Adj(v). Gọi p là một đường ngắn nhất từ s đến u chỉ đi qua các đỉnh thuộc St.Ta phải chứng minh dt[u] = w(p). Mà theo định nghĩa, dt[u] ≥ w(p), nên ta chỉ cần chứng minh dt[u] ≤ w(p). Trường hợp 1: p không đi qua v thì p chỉ đi qua các đỉnh thuộc St−1, nên theo giả thiết quy nạp, ta có: w(p) ≥ dt−1[u] ≥ dt[u]. Hình 2.2: Minh họa cho chứng minh ý 2 trường hợp 1. 25 Trường hợp 2: Nếu p đi qua v nhưng v không phải đỉnh kề trước của u trong p. Gọi z là đỉnh liền trước u trong p (z 6= v). Hình 2.3: Minh họa cho chứng minh ý 2 trường hợp 2. Vì z thêm vào tại thời điểm t′ ≤ t − 1 nên theo giả thiết quy nạp, tồn tại một đường đi ngắn nhất p′ từ s đến z sao cho p′ nằm trọn trong St−1. Suy ra δ(z) = dt−1[z] = w(p′). Ta gọi p1 là một đường đi từ s đến z qua v. Khi đó, w(p1) ≥ dt−1[z]. Đường p′ + (z, u) là một đường từ s đến u mà chỉ đi qua các đỉnh thuộc St−1 nên: w(p′ + (z, u)) ≥ dt−1[u]. Khi đó ta có: w(p) = w(p1) + d[z, u] ≥ w(p′) + d[z, u] ≥ dt−1[u] ≥ dt[u]. Vậy w(p) ≥ dt[u]. 26 Trường hợp 3: Nếu p đi qua v và v là đỉnh kề trước của u trong p. Hình 2.4: Minh họa cho chứng minh ý 2 trường hợp 3. Vì p là đường đi ngắn nhất từ s đến u mà chỉ đi qua các đỉnh thuộc St nên p′ là đường đi ngắn nhất từ s đến v mà chỉ đi qua các đỉnh thuộc St. Vì p′ là một đường đi đơn nên nó chỉ đi qua các đỉnh thuộc St\{v}, tức St−1. Theo giả thiết quy nạp ý 2 ứng với thời điểm t− 1, ta có w(p′) = dt−1[v]. Khi đó, w(p) = w(p′) + d[v, u] = dt−1[v] + d[v, u] ≥ dt[u] (Theo công thức tính dt[u]). Kết hợp 3 trường hợp, suy ra (2) được chứng minh. Vậy sau khi thuật toán kết thúc thì d[v] được cập nhật. Lưu ý: p(v) không dùng trong chứng minh nhưng trong thực tế lại cần sử dụng để tìm ra danh sách các đỉnh của đường đi. 27 2.2.3 Độ phức tạp của thuật toán Xét thấy, chi phí tìm v sao cho d[v] nhỏ nhất tốn O(log n), G = (V,E) có n đỉnh, vậy nên sẽ tốn thời gian là O(n log n) thời gian tìm v. Chi phí cập nhật: Tại mỗi bước, ta duyệt tất cả các cạnh đi ra (bằng bậc đi ra của một đỉnh). Vậy tổng chi phí cập nhật bằng tổng các bậc đi ra của các đỉnh, và bằng số cạnh. Hay chi phí cập nhật là O(m). Khi đó, trong trường hợp tổng quát, độ phức tạp của thuật toán là O(m + n log n). Nếu đồ thị G thưa, độ phức tạp là O(n log n). Nếu đồ thị G trù mật, độ phức tạp là O(n2). 2.2.4 Ví dụ Ví dụ áp dụng thuật toán Dijkstra tìm đường đi ngắn nhất trên đồ thị 2.5.a. Ta có, đỉnh nguồn là s, ta cần tìm đường đi ngắn nhất từ s tới các đỉnh còn lại. Hình 2.5: Thực thi thuật toán Dijkstra Giá trị d được viết trong các đỉnh. Các hình 2.5.b đến 2.5.f là kết quả của mỗi 28 bước thực hiện thuật toán. Kết thúc thuật toán, ta thu được đường đi ngắn nhất từ s tới các đỉnh là đường được tô đậm. 2.3 THUẬT TOÁN BELLMAN-FORD Trong phần trước, ta đã tìm hiểu thuật toán Dijkstra tìm đường đi ngắn nhất từ một đỉnh tới mọi đỉnh khác trong đồ thị có hướng với trọng số không âm trong thời gian O(m + n log n). Nếu đồ thị có trọng số âm, ta không thể áp dụng thuật toán Dijkstra được. Trong trường hợp này, ta sẽ áp dụng thuật toán Bellman-Ford. Ưu điểm của thuật toán Bellman-Ford là giúp phát hiện chu trình âm trong đồ thị. Điểm đặc biệt của đồ thị có trọng số âm là có thể có sự xuất hiện của chu trình âm. Sự xuất hiện này làm cho bài toán trở nên không xác định. Ví dụ một đồ thị tồn tại một chu trình âm là a → b → c → a. Ta muốn tìm đường đi ngắn nhất từ s đến đỉnh t. Ta có thể đi từ s đến a sau đó đi quanh chu trình âm vô hạn lần trước khi đến t. Tuy nhiên, nếu trong đồ thị không có chu trình âm, ta luôn có thể tìm được đường đi ngắn nhất từ một đỉnh đến mọi đỉnh khác trong đồ thị. Thuật toán tìm đường đi ngắn nhất trong đồ thị không có chu trình âm được phát triển bởi Bellman năm 1958 và Ford năm 1956, do đó, nó được đặt tên là thuật toán Bellman-Ford. 2.3.1 Mô tả thuật toán 29 Giả mã: Input: G = (V,E,w); s ∈ V Output:Một đường đi ngắn nhất từ s đến v SP (s, v);∀v ∈ V ; begin d[v]: độ dài đường đi ngắn nhất từ s đến v; p[v]: đỉnh trước v trong đường đi từ s đến v; for v ∈ V do if v = s then d[v] := 0; else d[v] :=∞; p[v] := null; end end for t := 1→ |V | − 1 do foreach (u, v) ∈ E do if d[u] + d[u, v] < d[v] then d[v] := d[u] + d[u, v]; p[v] := u; end end end foreach (u, v) ∈ E do if d[v] > d[u] + d[u, v] then Đồ thị chứa chu trình âm! return false; end end return true; end Algorithm 2: Thuật toán Bellman-Ford 30 2.3.2 Chứng minh tính đúng đắn của thuật toán Định lý 2.3.1. (Định lý tính đúng đắn của thuật toán Bellman-Ford) Sau vòng lặp t, với mọi đỉnh v ta có: 1. Nếu d[v] <∞ thì d[v] là độ dài một đường đi từ s đến v. 2. Nếu có một đường đi p từ s đến v đi qua nhiều nhất t cạnh thì dt[v] ≤ w(p). Khi kết thúc thuật toán, ta có d[v] = δ(v). Chứng minh. Ta chứng minh quy nạp theo t ≥ 0. Với t = 0, định lý trên đúng. Giả sử định lý trên đúng cho tới thời điểm t − 1. Ta cần chứng minh định lý đúng tại thời điểm t. Chứng minh 1: Nếu tại bước t − 1 đã có dt−1[v] < ∞. Suy ra tồn tại một đường đi từ s đến v (Do giả thiết quy nạp). Ngược lại, theo giả thiết quy nạp, tồn tại u sao cho dt[v] = dt[u] + d[u, v] <∞. Chứng minh 2: Có dt[u] ≤ dt−1[u] (vì d[u] không tăng). Nên: dt[v] = min{dt−1[v], dt[u] + d[u, v]} ≤ min{dt−1[v], dt−1[u] + d[u, v]}. Gọi p là một đường đi từ s đến v có nhiều nhất t cạnh. Trường hợp 1: p có nhiều nhất t− 1 cạnh. 31 Khi đó: w(p) ≥ dt−1[v]( theo giả thiết quy nạp tại thời điểm t− 1) ≥ dt[v]. Trường hợp 2: p có t cạnh. Hình 2.6: Minh họa cho chứng minh trường hợp 2 Gọi u là đỉnh liền trước của v trong p, p′ là một đường đi từ s đến u có t− 1 cạnh. Theo giả thiết quy nạp với u, ta có: w(p) = w(p′) + d[u, v] ≥ dt−1[u] + d[u, v] ≥ dt[v]. Suy ra dt[v] là độ dài một đường đi ngắn nhất từ s đến v có nhiều nhất t cạnh. 2.3.3 Độ phức tạp của thuật toán Đối với thuật toán Bellman-Ford, chi phí tính d[v] tốn O((n − 1).m), vì G = (V,E) có n đỉnh nên duyệt n− 1 vòng for, tại mỗi thời điểm lại xét tất cả các cặp cạnh, tốnm thời gian. 32 Chi phí kiểm tra chu trình âm: Ta duyệt tất cả các cặp cạnh của đồ thị. Vậy tổng chi phí cập nhật bằng bằng số cạnh. Hay chi phí cập nhật là O(m). Khi đó, trong trường hợp tổng quát, độ phức tạp của thuật toán là O(nm). 2.3.4 Ví dụ Ví dụ áp dụng thuật toán Bellman-Ford tìm đường đi ngắn nhất trên đồ thị 2.7.a. Ta có, đỉnh nguồn là s, ta cần tìm đường đi ngắn nhất từ s tới các đỉnh còn lại. Hình 2.7: Thực thi thuật toán Bellman-Ford Giá trị d được viết trong các đỉnh. Các hình 2.7.b đến 2.7.e là kết quả của mỗi bước thực hiện thuật toán. Kết thúc thuật toán, ta thu được đường đi ngắn nhất từ s tới các đỉnh là đường được tô đậm. 33 2.4 SO SÁNH Dựa vào các kết quả nêu trên cho thấy, với cùng một bài toán thì thuật toán Di- jkstra có thời gian chạy tốt hơn so với thuật toán Bellman-Ford, song lại không giải quyết được bài toán chứa cạnh trọng số âm. Do đó, thuật toán Bellman-Ford thường được sử dụng trong bài toán chứa cạnh có trọng số âm. Cả hai thuật toán này đều giải quyết bài toán tìm đường đi ngắn nhất nguồn đơn. Sự khác biệt chính của hai thuật toán là thuật toán Dijkstra không thể xử lý các cạnh có trọng số âm. Thuật toán Bellman-Ford có thể xử lý vấn đề đó. Tuy nhiên, phải nhắc lại rằng, nếu có một chu trình âm thì không có đường đi ngắn nhất. 34 CHƯƠNG 3 ỨNG DỤNG: BÀI TOÁN LẬP KẾ HOẠCH Trong thực tế, việc lập kế hoạch tiến độ là một trong những công cụ chính của quản lý dự án. Các hoạt động của dự án có thể được lập kế hoạch tiến độ với mức độ chi tiết khác nhau. Dự án là một tập hợp các hoạt động liên quan với nhau và phải được thực hiện theo một thứ tự nào đó cho đến khi hoàn thành toàn bộ các hoạt động. Hoạt động được hiểu là một việc đòi hỏi thời gian, nguyên liệu để hoàn thành. Việc lập kế hoạch cho biết thời điểm hoàn thành công việc. Cách tiếp cận cơ bản của các kỹ thuật lập kế hoạch là xây dựng một mạng lưới các công việc và mối liên hệ giữa chúng nhằm biểu diễn trình tự giữa các công việc trong dự án. Đồng thời cần xác định rõ các nhiệm vụ cần hoàn thành trước hay sau. Một số thuật ngữ được dùng phổ biến: Công việc (Task/Activity): là một nhiệm vụ hay một tập hợp các nhiệm vụ cụ thể mà dự án yêu cầu, nó tiêu dùng các nguồn lực và cần thời gian để hoàn thành. Sự kiện (Event): là kết quả của việc hoàn thành một hay nhiều công việc. Ta có 35 thể ghi nhận trạng thái kết thúc của các công việc tại một thời điểm cụ thể. Các sự kiện không sử dụng nguồn lực. Đường (Path): là một chuỗi các công việc liên tiếp nhau giữa hai sự kiện trong mạng. Đường tới hạn (Critical path): là các công việc, hay đường mà nếu nó trễ sẽ kéo dài thời gian hoàn thành dự án. Mỗi đường tới hạn của dự án có nghĩa là trình tự các công việc tới hạn (và sự kiện tới hạn) mà nối sự kiện bắt đầu dự án với sự kiện kết thúc dự án. 3.1 MÔ TẢ BÀI TOÁN Một dự án có thể chia thành nhiều công việc T1, . . . , Tn. Trong đó mỗi công việc có một khoảng thời gian dự kiến hoàn thành. Công việc T1 cần c1 đơn vị thời gian thực hiện Công việc T2 cần c2 đơn vị thời gian thực hiện . . . Giữa các công việc có thể có ràng buộc về thời gian, thứ tự, nguồn lực. Trong khuôn khổ luận văn, ta không xét đến việc nguồn lực của dự án: con người, máy móc, . . . , nên giả sử nguồn lực là vô tận, có thể chạy song song nhiều công việc. Có một số ràng buộc về thời gian như sau: Tj phải thực hiện sau Ti, Tk phải thực hiện sau Ti và Tj , 36 Tl phải thực hiện xong trước thời điểm xl, . . . Mục tiêu của bài toán: tính toán ngày kết thúc dự án sao cho sớm nhất. Ta cần tìm các thời điểm d1, d2, . . . , dn, f1, f2, . . . , fn sao cho: + Ti được bắt đầu thực hiện tại thời điểm

Các file đính kèm theo tài liệu này:

  • pdfluan_van_mot_so_bai_toan_toi_uu_tren_do_thi_va_ung_dung.pdf
Tài liệu liên quan