Giáo trình toán rời rạc phần 2 nguyễn gia định

101 1 0
Giáo trình toán rời rạc phần 2   nguyễn gia định

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

CHƯƠNG V MỘT SỐ BÀI TOÁN TỐI ƯU TRÊN ĐỒ THỊ 5.1 ĐỒ THỊ CĨ TRỌNG SỐ VÀ BÀI TỐN ĐƯỜNG ĐI NGẮN NHẤT 5.1.1 Mở đầu: Trong đời sống, thường gặp tình sau: để từ địa điểm A đến địa điểm B thành phố, có nhiều đường đi, nhiều cách đi; có lúc ta chọn đường ngắn (theo nghĩa cự ly), có lúc lại cần chọn đường nhanh (theo nghĩa thời gian) có lúc phải cân nhắc để chọn đường rẻ tiền (theo nghĩa chi phí), v.v Có thể coi sơ đồ đường từ A đến B thành phố đồ thị, với đỉnh giao lộ (A B coi giao lộ), cạnh đoạn đường nối hai giao lộ Trên cạnh đồ thị này, ta gán số dương, ứng với chiều dài đoạn đường, thời gian đoạn đường cước phí vận chuyển đoạn đường đó, Đồ thị có trọng số đồ thị G=(V,E) mà cạnh (hoặc cung) e∈E gán số thực m(e), gọi trọng số cạnh (hoặc cung) e Trong phần này, trọng số cạnh xét số dương gọi chiều dài cạnh Mỗi đường từ đỉnh u đến đỉnh v, có chiều dài m(u,v), tổng chiều dài cạnh mà qua Khoảng cách d(u,v) hai đỉnh u v chiều dài đường ngắn (theo nghĩa m(u,v) nhỏ nhất) đường từ u đến v Có thể xem đồ thị G đồ thị có trọng số mà cạnh có chiều dài Khi đó, khoảng cách d(u,v) hai đỉnh u v chiều dài đường từ u đến v ngắn nhất, tức đường qua cạnh 5.1.2 Bài tốn tìm đường ngắn nhất: Cho đơn đồ thị liên thơng, có trọng số G=(V,E) Tìm khoảng cách d(u0,v) từ đỉnh u0 cho trước đến đỉnh v G tìm đường ngắn từ u0 đến v Có số thuật tốn tìm đường ngắn nhất; đây, ta có thuật toán E Dijkstra, nhà toán học người Hà Lan, đề xuất năm 1959 Trong phiên mà ta trình bày, người ta giả sử đồ thị vơ hướng, trọng số dương Chỉ cần thay đổi đơi chút giải tốn tìm đường ngắn đồ thị có hướng Phương pháp thuật toán Dijkstra là: xác định đỉnh có khoảng cách đến u0 từ nhỏ đến lớn Trước tiên, đỉnh có khoảng cách đến a nhỏ a, với d(u0,u0)=0 Trong đỉnh v ≠ u0, tìm đỉnh có khoảng cách k1 đến u0 nhỏ Đỉnh phải đỉnh kề với u0 Giả sử u1 Ta có: d(u0,u1) = k1 Toán rời rạc - Nguyễn Gia Định 67 Trong đỉnh v ≠ u0 v ≠ u1, tìm đỉnh có khoảng cách k2 đến u0 nhỏ Đỉnh phải đỉnh kề với u0 với u1 Giả sử u2 Ta có: d(u0,u2) = k2 Tiếp tục trên, tìm khoảng cách từ u0 đến đỉnh v G Nếu V={u0, u1, , un} thì: = d(u0,u0) < d(u0,u1) < d(u0,u2) < < d(u0,un) 5.1.3 Thuật toán Dijkstra: procedure Dijkstra (G=(V,E) đơn đồ thị liên thơng, có trọng số với trọng số dương) {G có đỉnh a=u0, u1, , un=z trọng số m(ui,uj), với m(ui,uj) = ∞ (ui,uj) không cạnh G} for i := to n L(ui) := ∞ L(a) := S := V \ {a} u := a while S ≠ ∅ begin for tất đỉnh v thuộc S if L(u) +m(u,v) < L(v) then L(v) := L(u)+m(u,v) u := đỉnh thuộc S có nhãn L(u) nhỏ {L(u): độ dài đường ngắn từ a đến u} S := S \ {u} end Thí dụ 1: Tìm khoảng cách d(a,v) từ a đến đỉnh v tìm đường ngắn từ a đến v cho đồ thị G sau b 1 a 2 Toán rời rạc - Nguyễn Gia Định e n c d g m 68 h k L(a) L(b) L(c) L(d) L(e) L(g) L(h) L(k) L(m) L(n) ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ ∞ − ∞ ∞ ∞ ∞ ∞ − − ∞ ∞ ∞ ∞ − − ∞ ∞ ∞ ∞ − − − ∞ − ∞ ∞ − − − ∞ − ∞ − − − − − 10 − ∞ − − − − − − − − − − − − − − − − − − − − − − − − − − 5.1.4 Định lý: Thuật tốn Dijkstra tìm đường ngắn từ đỉnh cho trước đến đỉnh tuỳ ý đơn đồ thị vô hướng liên thơng có trọng số Chứng minh: Định lý chứng minh quy nạp Tại bước k ta có giả thiết quy nạp là: (i) Nhãn đỉnh v không thuộc S độ dài đường ngắn từ đỉnh a tới đỉnh này; (ii) Nhãn đỉnh v S độ dài đường ngắn từ đỉnh a tới đỉnh đường chứa đỉnh (ngồi đỉnh này) khơng thuộc S Khi k=0, tức chưa có bước lặp thực hiện, S=V \ {a}, độ dài đường ngắn từ a tới đỉnh khác a ∞ độ dài đường ngắn từ a tới (ở đây, cho phép đường khơng có cạnh) Do bước sở Giả sử giả thiết quy nạp với bước k Gọi v đỉnh lấy khỏi S bước lặp k+1, v đỉnh thuộc S cuối bước k có nhãn nhỏ (nếu có nhiều đỉnh có nhãn nhỏ chọn đỉnh làm v) Từ giả thiết quy nạp ta thấy Toán rời rạc - Nguyễn Gia Định 69 trước vào vòng lặp thứ k+1, đỉnh không thuộc S gán nhãn độ dài đường ngắn từ a Đỉnh v phải gán nhãn độ dài đường ngắn từ a Nếu điều không xảy cuối bước lặp thứ k có đường với độ dài nhỏ Lk(v) chứa đỉnh thuộc S (vì Lk(v) độ dài đường ngắn từ a tới v chứa đỉnh không thuộc S sau bước lặp thứ k) Gọi u đỉnh đường thuộc S Đó đường với độ dài nhỏ Lk(v) từ a tới u chứa đỉnh không thuộc S Điều trái với cách chọn v Do (i) cịn cuối bước lặp k+1 Gọi u đỉnh thuộc S sau bước k+1 Đường ngắn từ a tới u chứa đỉnh không thuộc S chứa v khơng Nếu khơng chứa v theo giả thiết quy nạp độ dài Lk(v) Nếu chứa v tạo thành đường từ a tới v với độ dài ngắn chứa đỉnh không thuộc S khác v, kết thúc cạnh từ v tới u Khi độ dài Lk(v)+m(v,u) Điều chứng tỏ (ii) Lk+1(u)=min(Lk(u), Lk(v)+m(v,u)) 5.1.5 Mệnh đề: Thuật tốn Dijkstra tìm đường ngắn từ đỉnh cho trước đến đỉnh tuỳ ý đơn đồ thị vơ hướng liên thơng có trọng số có độ phức tạp O(n2) Chứng minh: Thuật tốn dùng khơng q n−1 bước lặp Trong bước lặp, dùng không 2(n−1) phép cộng phép so sánh để sửa đổi nhãn đỉnh Ngoài ra, đỉnh thuộc Sk có nhãn nhỏ nhờ khơng q n−1 phép so sánh Do thuật tốn có độ phức tạp O(n2) 5.1.6 Thuật toán Floyd: Cho G=(V,E) đồ thị có hướng, có trọng số Để tìm đường ngắn cặp đỉnh G, ta áp dụng thuật tốn Dijkstra nhiều lần áp dụng thuật tốn Floyd trình bày Giả sử V={v1, v2, , vn} có ma trận trọng số W ≡ W0 Thuật toán Floyd xây dựng dãy ma trận vuông cấp n Wk (0 ≤ k ≤ n) sau: procedure Xác định Wn for i := to n for j := to n W[i,j] := m(vi,vj) {W[i,j] phần tử dòng i cột j ma trận W0} for k := to n if W[i,k] +W[k,j] < W[i,j] then W[i,j] := W[i,k] +W[k,j] {W[i,j] phần tử dòng i cột j ma trận Wk} 5.1.7 Định lý: Thuật toán Floyd cho ta ma trận W*=Wn ma trận khoảng cách nhỏ đồ thị G Toán rời rạc - Nguyễn Gia Định 70 Chứng minh: Ta chứng minh quy nạp theo k mệnh đề sau: Wk[i,j] chiều dài đường ngắn đường nối đỉnh vi với đỉnh vj qua đỉnh trung gian {v1, v2, , vk} Trước hết mệnh đề hiển nhiên với k=0 Giả sử mệnh đề với k-1 Xét Wk[i,j] Có hai trường hợp: 1) Trong đường chiều dài ngắn nối vi với vj qua đỉnh trung gian {v1, v2, , vk}, có đường γ cho vk ∉ γ Khi γ đường ngắn nối vi với vj qua đỉnh trung gian {v1, v2, , vk-1}, nên theo giả thiết quy nạp, Wk-1[i,j] = chiều dài γ ≤ Wk-1[i,k]+Wk-1[k,j] Do theo định nghĩa Wk Wk[i,j]=Wk-1[i,j] 2) Mọi đường chiều dài ngắn nối vi với vj qua đỉnh trung gian {v1, v2, , vk}, chứa vk Gọi γ = vi vk vj đường ngắn v1 vk vk vj đường ngắn qua đỉnh trung gian {v1, v2, , vk-1} Wk-1[i,k]+Wk-1[k,j] = chiều dài(v1 vk) + chiều dài(vk vj) = chiều dài γ < Wk-1[i,j] Do theo định nghĩa Wk ta có: Wk[i,j] = Wk-1[i,k]+Wk-1[k,j] Thí dụ 2: Xét đồ thị G sau: v1 2 1 v3 v4 v2 v5 v6 Áp dụng thuật tốn Floyd, ta tìm (các trống ∞) ⎞ ⎛ ⎟ ⎜ ⎟ ⎜ ⎜ 3⎟ ⎟ W = W0 = ⎜ ⎟ ⎜ ⎟ ⎜2 ⎟ ⎜ ⎟ ⎜ ⎠ ⎝ Toán rời rạc - Nguyễn Gia Định 71 ⎛ ⎜ ⎜ ⎜ W1 = ⎜ ⎜ ⎜2 ⎜ ⎜ ⎝ ⎞ ⎟ ⎟ 3⎟ ⎟ , W2 = ⎟ ⎟ ⎟ ⎟ ⎠ ⎛ ⎜ ⎜ ⎜ ⎜ ⎜ ⎜2 ⎜ ⎜ ⎝ ⎛ ⎜ ⎜ ⎜ W3 = ⎜ ⎜ ⎜2 ⎜ ⎜ ⎝ 11 14 ⎞ ⎟ 7⎟ 3⎟ ⎟ , W4 = 11 ⎟ 10 ⎟⎟ ⎟⎠ ⎛ ⎜ ⎜ ⎜ ⎜ ⎜ ⎜2 ⎜ ⎜ ⎝ 10 13 ⎞ ⎟ ⎟ ⎟ ⎟ 11 ⎟ ⎟⎟ ⎟⎠ 7 11 4 10 ⎞ ⎟ ⎟ 3⎟ ⎟ ⎟ ⎟ ⎟ ⎟ ⎠ ⎛ 9 12 ⎞ ⎛ 9 12 ⎞ ⎟ ⎟ ⎜ ⎜ ⎜3 ⎟ ⎜3 ⎟ ⎜ ⎜7 ⎟ 3⎟ ⎟ , W* = W6 = ⎜ ⎟ W5 = ⎜ ⎜ 7 10 ⎟ ⎜ 7 10 ⎟ ⎜2 ⎟ ⎜2 ⎟ ⎟ ⎟ ⎜ ⎜ ⎜4 ⎟ ⎜4 ⎟ ⎠ ⎠ ⎝ ⎝ Thuật toán Floyd áp dụng cho đồ thị vơ hướng đồ thị có hướng Ta cần thay cạnh vơ hướng (u,v) cặp cạnh có hướng (u,v) (v,u) với m(u,v)=m(v,u) Tuy nhiên, trường hợp này, phần tử đường chéo ma trận W cần đặt Đồ thị có hướng G liên thông mạnh phần tử nằm đường chéo ma trận trọng số ngắn W* hữu hạn 5.2 BÀI TOÁN LUỒNG CỰC ĐẠI 5.2.1 Luồng vận tải: 5.2.1.1 Định nghĩa: Mạng vận tải đồ thị có hướng, khơng có khuyên có trọng số G=(V,E) với V={v0, v1, , vn} thoả mãn: 1) Mỗi cung e ∈ E có trọng số m(e) số ngun khơng âm gọi khả thông qua cung e 2) Có đỉnh v0 khơng có cung vào, tức degt(v0)=0 Đỉnh v0 gọi lối vào hay đỉnh phát mạng 3) Có đỉnh khơng có cung ra, tức dego(vn)=0 Đỉnh gọi lối hay đỉnh thu mạng Toán rời rạc - Nguyễn Gia Định 72 5.2.1.2 Định nghĩa: Để định lượng khai thác, tức xác định lượng vật chất chuyển qua mạng vận tải G=(V,E), người ta đưa khái niệm luồng vận tải định nghĩa sau Hàm ϕ xác định tập cung E nhận giá trị nguyên gọi luồng vận tải mạng vận tải G ϕ thoả mãn: 1) ϕ(e) ≥ 0, ∀e ∈ E 2) ∑ ϕ (e) = ∑ ϕ (e) , ∀v ∈V, v≠v0, v≠vn Ở đây, Γ − (v)={e∈E | e có đỉnh cuối v}, e∈Γ − ( v ) e∈Γ + ( v ) Γ + (v)={e∈E | e có đỉnh đầu v} 3) ϕ(e) ≤ m(e), ∀e ∈ E Ta xem ϕ(e) lượng hàng chuyển cung e=(u,v) từ đỉnh u đến đỉnh v không vượt khả thơng qua cung Ngồi ra, từ điều kiện 2) ta thấy v lối vào v0 hay lối vn, lượng hàng chuyển tới v lượng hàng chuyển khỏi v Từ quan hệ 2) suy ra: 4) ∑ ϕ (e) = ∑ ϕ (e) =: ϕ e∈Γ + ( v0 ) e∈Γ − ( ) Đại lượng ϕ (ta ký hiệu ϕ n ) gọi luồng qua mạng, hay cường độ luồng điểm hay giá trị luồng ϕ Bài tốn đặt tìm ϕ để ϕ đạt giá trị lớn nhất, tức tìm giá trị lớn luồng 5.2.1.3 Định nghĩa: Cho mạng vận tải G=(V,E) A ⊂ V Ký hiệu Γ − (A)={(u,v)∈E | v∈A, u∉A}, Γ + (A)={(u,v)∈E | u∈A, v∉A} Đối với tập cung M tuỳ ý, đại lượng ϕ(M)= ∑ ϕ (e) gọi luồng tập e∈M cung M Từ điều kiện 2) dễ dàng suy hệ sau 5.2.1.4 Hệ quả: Cho ϕ luồng mạng vận tải G=(V,E) A ⊂ V \{v0,vn} Khi đó: ϕ( Γ − (A))=ϕ( Γ + (A)) 5.2.2 Bài toán luồng cực đại: Cho mạng vận tải G=(V,E) Hãy tìm luồng ϕ để đạt ϕ max mạng G Nguyên lý thuật toán giải tốn tìm luồng cực đại sau 5.2.2.1 Định nghĩa: Cho A ⊂ V tập tuỳ ý không chứa lối vào v0 chứa lối Tập Γ − (A) gọi thiết diện mạng vận tải G Đại lượng m( Γ − (A))= ∑ m ( e) gọi khả thông qua thiết diện − e∈Γ ( A) Γ − (A) Toán rời rạc - Nguyễn Gia Định 73 Từ định nghĩa thiết diện khả thông qua ta nhận thấy rằng: đơn vị hàng hố chuyển từ v0 đến phải lần qua cung thiết diện Γ − (A) Vì vậy, dù luồng ϕ thiết diện Γ − (A) thoả mãn quan hệ: ϕn ≤ m( Γ − (A)) Do đó, luồng ϕ thiết diện W mà có: ϕn = m(W) chắn luồng ϕ đạt giá trị lớn thiết diện W có khả thơng qua nhỏ 5.2.2.2 Định nghĩa: Cung e mạng vận tải G với luồng vận tải ϕ goi cung bão hoà ϕ(e)=m(e) Luồng ϕ mạng vận tải G gọi luồng đầy đường từ v0 đến chứa cung bão hoà Từ định nghĩa ta thấy rằng, luồng ϕ mạng vận tải G chưa đầy định tìm đường α từ lối vào v0 đến lối khơng chứa cung bão hồ Khi ta nâng luồng ϕ thành ϕ’ sau: ⎧ϕ (e) + e∈α , ϕ ' (e) = ⎨ e∉α ⎩ϕ (e) Khi ϕ’ luồng, mà giá trị là: ϕ’n = ϕn +1 > ϕn Như vậy, luồng khơng đầy ta nâng giá trị nâng nhận luồng đầy Tuy vậy, thực tế cho thấy có luồng đầy, chưa đạt tới giá trị cực đại Bởi vậy, cần phải dùng thuật tốn Ford-Fulkerson để tìm giá trị cực đại luồng 5.2.2.3 Thuật tốn Ford-Fulkerson: Để tìm luồng cực đại mạng vận tải G, ta xuất phát từ luồng tuỳ ý ϕ G, nâng luồng lên đầy, sau áp dụng thuật tốn Ford-Fulkerson ta áp dụng thuật toán Ford-Fulkerson trực tiếp luồng ϕ Thuật toán gồm bước: Bước (đánh dấu đỉnh mạng): Lối vào v0 đánh dấu 1) Nếu đỉnh vi đánh dấu ta dùng số +i để đánh dấu cho đỉnh y chưa đánh dấu mà (vi,y)∈E cung chưa bão hoà (ϕ(vi,y)0) Toán rời rạc - Nguyễn Gia Định 74 Nếu với phương pháp ta đánh dấu tới lối G tồn v0 xích α, đỉnh khác đánh dấu theo số đỉnh liền trước (chỉ sai khác dấu) Khi chắn ta nâng giá trị luồng Bước (nâng giá trị luồng): Để nâng giá trị luồng ϕ, ta đặt: ϕ’(e) = ϕ(e), e∉α, ϕ’(e) = ϕ(e)+1, e∈α định hướng theo chiều xích α từ vo đến vn, ϕ’(e) = ϕ(e)−1, e∈α định hướng ngược với chiều xích α từ vo đến +i y vj -j e z vi v0 ϕ’ thoả mãn điều kiện luồng, nên ϕ’ luồng ta có: ϕ’n = ϕn+1 Như vậy, ta nâng luồng lên đơn vị Sau lặp lại vịng Vì khả thơng qua cung hữu hạn, nên trình phải dừng lại sau số hữu hạn bước Bước 3: Nếu với luồng ϕ0 phương pháp ta nâng giá trị luồng lên nữa, nghĩa ta đánh dấu đỉnh vn, ta nói q trình nâng luồng kết thúc ϕ0 đạt giá trị cực đại, đồng thời gọi ϕ0 luồng kết thúc Khi mạng vận tải G=(V,E) đạt tới luồng ϕ0, bước ta khơng thể đánh dấu tới lối Trên sở trạng đánh dấu bước này, ta chứng minh luồng ϕ0 đạt giá trị cực đại 5.2.2.4 Bổ đề: Cho luồng ϕ mạng vận tải G=(V,E) A ⊂ V, chứa lối không chứa lối vào v0 Khi đó: ϕ = ϕ (Γ − ( A)) − ϕ (Γ + ( A)) Chứng minh: Đặt A1=A \{vn} Theo Hệ 5.2.1.4, ta có: ϕ (Γ − ( A1 )) = ϕ (Γ + ( A1 )) (1) Đặt C1={(a,vn)∈E | a∉A} Khi Γ − ( A) = Γ − ( A1 ) ∪ C1 Γ − ( A1 ) ∩ C1 = ∅, nên ϕ (Γ − ( A)) = ϕ (Γ − ( A1 )) + ϕ (C1) (2) Đặt C2={(b,vn)∈E | b∈A1} Khi C2={(b,vn)∈E | b∈A}, Γ + ( A1 ) = Γ + ( A) ∪ C2 Γ + ( A) ∩ C2 = ∅, nên ϕ (Γ + ( A)) = ϕ (Γ + ( A1 )) − ϕ (C2) (3) Toán rời rạc - Nguyễn Gia Định 75 Ngoài ra, Γ − (v n ) = C1∪C2 C1∩C2 = ∅, nên ϕ = ϕ (Γ − (v n )) = ϕ (C1)+ ϕ (C2) (4) Từ (1), (2), (3) (4), ta có: ϕ = ϕ (Γ − ( A)) − ϕ (Γ + ( A)) 5.2.2.5 Định lý (Ford-Fulkerson): Trong mạng vận tải G=(V,E), giá trị lớn luồng khả thông qua nhỏ thiết diện, nghĩa max ϕ = ϕ A⊂V ,v0∉A,vn∈A m(Γ − ( A)) Chứng minh: Giả sử mạng vận tải G, ϕ0 luồng cuối cùng, mà sau phương pháp đánh dấu thuật tốn Ford-Fulkerson khơng đạt tới lối Trên sở trạng đánh dấu lần cuối này, ta dùng B để ký hiệu tập gồm đỉnh G khơng đánh dấu Khi v0∉B, vn∈B Do Γ − (B) thiết diện mạng vận tải G theo Bổ đề 5.2.2.4, ta có: ϕ v0 = ϕ (Γ − ( B)) − ϕ (Γ + ( B)) (1) n Đối với cung e=(u,v)∈ Γ − (B) u∉B v∈B, tức u đánh dấu v không đánh dấu, nên theo nguyên tắc đánh dấu thứ nhất, e cung bão hoà: ϕ0(e) = m(e) ϕ (Γ − ( B)) = Do đó, ∑ ϕ (e) = ∑ m(e) = m(Γ − ( B)) − (2) − e∈Γ ( B ) + e∈Γ ( B ) Đối với cung e=(s,t)∈ Γ (B) s∈B t∉B, tức s khơng đánh dấu t đánh dấu, nên theo nguyên tắc đánh dấu thứ hai: ϕ0(e) = ϕ (Γ + ( B)) = Do đó, ∑ ϕ ( e) = (3) + e∈Γ ( B ) Từ (1), (2) (3) ta suy ra: ϕ v0 = m(Γ − ( B)) n Vì vậy, ϕ v0 n giá trị lớn luồng đạt được, m( Γ − (B)) giá trị nhỏ khả thông qua thiết diện thuộc mạng vận tải G Thí dụ 3: Cho mạng vận tải hình với khả thơng qua đặt khun trịn, luồng ghi cung Tìm luồng cực đại mạng Luồng ϕ có đường (v0,v4), (v4,v6), (v6,v8) gồm cung chưa bão hồ nên chưa đầy Do nâng luồng cung lên đơn vị, để ϕ1 Do đường xuất phát từ v0 đến v8 chứa cung bão hoà, nên luồng ϕ1 luồng đầy Song chưa phải luồng cực đại Áp dụng thuật toán Ford-Fulkerson để nâng luồng ϕ1 Toán rời rạc - Nguyễn Gia Định 76 G.SoDinh:=G.SoDinh-1; Setlength(G.DSDinh,G.SoDinh); Setlength(Index,G.SoCanh); N:=0;Start:=-1; For i:=0 to G.SoCanh-1 If (G.DSCanh[i].DinhDau=DinhDown)or(G.DSCanh[i].DinhCuoi=DinhDown) then begin If Start=-1 then Start:=N; end else begin Index[N]:=i; N:=N+1; end; If Start-1 then begin G.SoCanh:=N; For i:=Start to G.SoCanh-1 G.DSCanh[i]:=G.DSCanh[Index[i]]; For i:=0 to G.SoCanh-1 With G.DSCanh[i] begin If DinhDau>DinhDown then DinhDau:=DinhDau-1; If DinhCuoi>DinhDown then DinhCuoi:=DinhCuoi-1; end; Setlength(G.DSCanh,G.SoCanh); end; Setlength(Index,0); HienThamSoCung(G); VeDoThi(G,Pic,imagelist1); DrawPaint(PaintBox1,Pic); FileChanged:=True; end; procedure TForm2.DeleteAll1Click(Sender: TObject); begin G.SoDinh:=0;G.SoCanh:=0; Setlength(G.DSDinh,0);Setlength(G.DSCanh,0); Pic.Canvas.Brush.Style:=bsSolid; Pic.Canvas.Pen.Style:=psSolid; Pic.Canvas.Brush.Color:=rgb(255,255,255); Pic.Canvas.Pen.Color:=rgb(255,255,255); Pic.Canvas.FillRect(Rect(0,0,Pic.Width,Pic.Height)); DrawPaint(PaintBox1,Pic); FileChanged:=true; end; 153 procedure TForm2.Save1Click(Sender: TObject); var F:textfile; i:integer; begin SaveDialog1.DefaultExt:='*.GRD'; SaveDialog1.Filter:='Graph data file (*.GRD)|*.GRD'; If not SaveDialog1.Execute then exit; AssignFile(F,SaveDialog1.FileName); Rewrite(F); Try Writeln(f,G.Sodinh,' ',G.Socanh); For i:=0 to G.SoDinh-1 Writeln(F,G.DSDinh[i].ToaDo.x,' ',G.DSDinh[i].ToaDo.y,' ',G.DSDinh[i].Ten); For i:=0 to G.SoCanh-1 Writeln(F,G.DSCanh[i].DinhDau,' ',G.DSCanh[i].DinhCuoi,' ',G.DSCanh[i].TrongSo.Gia); except Showmessage('Writting error'); end; CloseFile(F); FileChanged:=false; end; procedure TForm2.Open1Click(Sender: TObject); Var F:TextFile; i:integer; begin OpenDialog1.DefaultExt:='*.GRD'; OpenDialog1.Filter:='Graph data file (*.GRD)|*.GRD'; If not OpenDialog1.Execute then exit; AssignFile(F,OpenDialog1.FileName); ReSet(F); Try Readln(f,G.Sodinh,G.Socanh); Setlength(G.DSDinh,G.SoDinh); Setlength(G.DSCanh,G.SoCanh); For i:=0 to G.SoDinh-1 begin Readln(F,G.DSDinh[i].ToaDo.x,G.DSDinh[i].ToaDo.y,G.DSDinh[i].Ten); G.DSDinh[i].Ten:=trimleft(G.DSDinh[i].Ten); G.DSDinh[i].MucKichHoat:=0; end; 154 For i:=0 to G.SoCanh-1 Readln(F,G.DSCanh[i].DinhDau,G.DSCanh[i].DinhCuoi,G.DSCanh[i].TrongSo.Gia); except DeleteGraph(G); showmessage('Error struct file'); CloseFile(F); Self.Caption:='Graph Algorithm - New document'; VeDoThi(G,Pic,imagelist1); DrawPaint(PaintBox1,Pic); exit; end; CloseFile(F); VeDoThi(G,Pic,imagelist1); DrawPaint(PaintBox1,Pic); Filename:=OpenDialog1.FileName; Self.Caption:='Graph Algorithm - ' + Filename; FileChanged:=False; end; procedure TForm2.SpeedButton1Click(Sender: TObject); var D1,D2,ChiSo,i:integer; begin TimCacDinhKichHoat(G,D1,D2); If Not SpeedButton1.Down then begin Timcung(G,D2,D1,ChiSo); for i:=Chiso to G.SoCanh-2 G.DSCanh[i]:=G.DSCanh[i+1]; G.SoCanh:=G.SoCanh-1; Setlength(G.DSCanh,G.SoCanh); end else begin G.SoCanh:=G.SoCanh+1; Setlength(G.DSCanh,G.SoCanh); With G.DSCanh[G.SoCanh-1] begin DinhDh); begin SaveDialog1.DefaultExt:='*.JPG'; SaveDialog1.Filter:='Bitmap image (*.BMP)|*.BMP|Jpeg image (*.JPG)|*.JPG'; SaveDialog1.FilterIndex:=2; If not SaveDialog1.Execute then exit; case SaveDialog1.FilterIndex of 1:{BMP} Pic.SaveToFile(SaveDialog1.FileName); 2:{Jpeg} begin T:=TJpegimage.Create; T.Assign(Pic); try T.SaveToFile(SaveDialog1.FileName); finally T.Free end; end; end end; end Chương trình cài đặt sau: program Project1; uses Forms, Func_DoThi in 'Func_DoThi.pas', Unit2 in 'Unit2.pas' {Form2}, {$R *.res} begin Application.Initialize; Application.CreateForm(TForm2, Form2); Application.Run; end 157 PH N PH L C Ph l c Bài toán lu ng c c i Cho mạng G=(V,E) Hãy tìm luồng f* mạng với giá trị luồng val(f*) lớn Luồng ta gọi luồng cực đại mạng Bài toán xuất nhiều ứng dụng thực tế Chẳng hạn cần xác định cường độ lớn dòng vận tải hai nút đồ giao thơng Trong thí dụ lời giải toán luồng cực đại cho ta đoạn đường xe đông chúng tạo thành chỗ hẹp tương ứng dịng giao thơng xét theo hai nút chọn Một thí dụ khác xét đồ thị tương ứng với hệ thống đường ống dẫn dầu, ống tương ứng với cung, điểm phát coi tàu chở dầu, điểm thu bể chứa, điểm nối ống nút đồ thị, khả thông qua cung tương ứng với tiết diện ống Cần phải tìm luồng dầu lớn bơm dầu từ tàu chở dầu vào bể chứa nh lý: Các mệnh đề tương đương: (i) f luồng cực đại mạng (ii) Khơng tìm đường tăng luồng f (iii) Val(f)=c(X,X*) với lát cắt (X,X*) (Ta gọi lát cắt (X,X*) cách phân hoạch tập đỉnh V mạng thành hai tập X X*=V\X, s ∈ X t ∈ X*.) Định lý sở để xây dựng thuật toán lặp sau để tìm luồng cực đại mạng: Bắt đầu từ luồng tất cung (ta gọi luồng luồng không), lặp lại bước lặp sau thu luồng mà khơng cịn đường tăng: Bước lặp tăng luồng (Ford – Fulkerson): Tìm đường tăng P luồng có, tăng luồng dọc theo đường P Khi có luồng cực đại, lát cắt hẹp tìm theo thủ tục mơ tả việc chứng minh định lý Thuật toán Ford-Fulkerson mô tả thủ tục sau đây: Procedure Luongcucdai; Begin Stop := false; While not Stop If < Tìm đường tăng luồng P> then < Tăng luồng dọc theo P> Else Stop := true; End; 158 Để tìm đường tăng luồng G(f) sử dụng thuật tốn tìm kiếm theo chiều rộng (hay tìm kiếm theo chiều sâu), đỉnh s khơng cần xây dựng tường minh đồ thị G(f) Ford-Fulkerson đề nghị thuật toán gán nhãn chi tiết sau để giải toán luồng cực đại mạng Thuật toán luồng chấp nhận mạng (có thể luồng khơng) , sau ta tăng luồng cách tìm đường tăng luồng Để tìm đường tăng luồng ta áp dụng phương pháp gán nhãn cho đỉnh Mỗi đỉnh q trình thực thuật tốn ba trạng thái: chưa có nhãn, có nhãn chưa xét, có nhãn xét Nhãn đỉnh v gồm hai phần có hai dạng sau : [ + p(v) , ε (v) ] [ − p(v), ε (v) ] Phần thứ +p(v) (-p(v)) cần tăng giảm luồng theo cung (p(v),v)( cung (v,p(v)) phần thứ hai ε (v) lượng lớn tăng giảm luồng theo cung Đầu tiên có đỉnh s khởi tạo nhãn nhãn chưa xét, cịn tất đỉnh cịn lại chưa có nhãn Từ s ta gán nhãn cho tất đỉnh kề với nhãn đỉnh s trở thành xét Tiếp theo, từ đỉnh v có nhãn chưa xét ta lại gán nhãn cho tất đỉnh chưa có nhãn kề với nhãn đỉnh v trở thành xét Quá trình lặp lại đỉnh t trở thành có nhãn nhãn tất đỉnh có nhãn đầu xét đỉnh t khơng có nhãn Trong trường hợp thứ ta tìm đường tăng luồng, cịn trường hợp thứ hai luồng xét không tồn đường tăng luồng (tức luồng cực đại) Mỗi tìm đường tăng luồng, ta lại tăng luồng theo đường tìm được, sau xố tất nhãn đổi với luồng thu lại sử dụng phép gán nhãn đỉnh để tìm đường tăng luồng Thuật toán kết thúc luồng có mạng khơng tìm đường tăng luồng Hai thủ tục tìm đường tăng luồng mơ tả sau : Procedure Find-path; { Thủ tục gán nhãn đường tăng luồng p[v], ∈ ε [v] nhãn đỉnh v; VT danh sách đỉnh có nhãn chưa xét ; c[u,v] khả thông qua cung (u,v),u,v ∈ V; f[u,v] luồng cung (u,v), (u,v ∈ V); } BEGIN p[s] := s ; ε [s] := +∞ ; VT := {s}; Pathfound := true; While VT {} 159 BEGIN u ⇐ VT ;( * lấy u từ VT *) For v ∈ V If (v chưa có nhãn) then Begin If (c[u,v] >0) and (f[u,v] < c[u,v] ) then Begin P[v] := u ; ε [v] := { ε [u],c[u,v]-f[u,v] }; VT:=VT ∪ {v};(* nạp v vào danh sách đỉnh có nhãn *) If v = t then exit; End Else If (c[v,u] > 0) and (f[v,u] < 0) then Begin P[v] := u ; ε [v] := { ε [u] , f[u,v] }; VT:=VT ∪ {v};(* nạp v vào danh sách đỉnh có nhãn *) If v = t then exit; End; End; End; PathFound :=false; End; Procedure Inc_flow ; { thuật toán tăng luồng theo đường tăng } Begin v := t ; u := t ; tang := [t]; while u s begin v := p[u]; if v > then f[v,u] := f[v,u] + tang else begin v := -v; f[u,v] :=f[u,v] –tang; end; u := v ; 160 end; Procedure FF; { thủ tục thể thuật toán Ford_fulkerson } Begin (* khởi tạo luồng với giá trị *) For u ∈ V For v ∈ V f[u,v] :=0; Stop := false; While not Stop begin find_path; If pathfound then Inc_flow Else Stop:=true; End; < Luồng cực đại mạng f[u,v], u,v ∈ V > < Lát cắt hẹp (VT , V\ VT) > End; Chương trình sau chương trình phục vụ cho việc học tập giảng dạy tốn tìm luồng cực đại mạng Chương trình sau xây dựng cơng cụ lập trình Delphi Các ch c n ng c a ch ng trình: Ta xây dựng chương trình bao gồm chức sau: * Tóm tắt thuật tốn Ford – Fulkeson * Hiển thị bước thực ứng với ví dụ cụ thể Tóm t t thu t tốn Ford – Fulkerson : Chức có mục đích giúp cho người sử dụng nắm vững thuật toán trước vào thí dụ cụ thể Hi n th b c th c hi n c a tốn: Do chương trình nhằm mục đích phục vụ cho việc dạy học mơn Tốn rời rạc nên chức việc hiển thị chi tiết bước giải tốn ứng với tưng thí dụ cụ thể giúp cho người sử dụng hiểu rõ thuật toán C u trúc d li u cài t thu t toán: C u trúc d li u: Đồ thị lưu giữ dạng tập đỉnh tập cạnh Mỗi đỉnh lưu theo cấu trúc Record sau: 161 L_TypeDinh = record Ten:String; ToaDo:L_TypeToaDo; MucKichHoat:Byte; end; Trong đó: - Biến Ten có kiểu String , lưu giữ tên đỉnh (mặt định V0,V1,…) - Biến ToaDo có kiểu L_TypeToaDo, lưu giữ toạ độ x, y đỉnh có cấu trúc Record sau : L_TypeToaDo = record x,y:integer; end; Biến Muckichhoat có kiểu Byte lưu giữ mức độ kích hoạt đỉnh (mỗi đỉnh có mức kích hoạt khác nhau), biến dùng để xác định đỉnh đầu, đỉnh cuối, đỉnh hẹp… Tập cạnh đồ thị lưu theo cấu trúc Record, cấu trúc cạnh lưu trữ sau: L_TypeCanh = record DinhDau,DinhCuoi:Integer; TrongSo:L_TypeChiphi; end; : Biến DinhDau có kiểu Integer, lưu giữ số đỉnh đầu cạnh Biến DinhCuoi có kiểu Integer, lưu giữ số đỉnh cuối cạnh Biến TrongSo có kiểu L_TypeChiPhi, lưu giữ giá khả thông qua cạnh xét Kiểu L_TypeChiPhi Record có dạng sau : L_TypeChiPhi = record Gia:real; kntq:real; end; Cài t thu t toán: Như trình bày phần , thuật tốn Ford –Fulkerson cài đặt cách kết hợp thủ tục Find-Path (thủ tục gán nhãn tìm đường tăng luồng) Inc-Flow (thủ tục tăng luồng theo đường tăng) Đây phần cài đặt chi tiết thuật toán Ford – Fulkerson (viết theo ngơn ngữ lập trình Delphi): 162 procedure L_find_path(var L_G1:L_typedothi); { thu tuc gan nhan tim duong tang luong: L_p[v],L_nhan,L_e[v] la nhan cua dinh v; L_v la danh sach cac dinh co nhan nhung chua xet; } VAR x,y:integer; ok:boolean; a1,b1,k1,l1:real; t,t1,i:integer; BEGIN for i:=0 to L_G1.sodinh-1 L_p1[i]:=-1; L_p1[0]:=0; L_nhan[0]:=true; L_e[0]:=vocung; L_v:=[0] ; L_v1:=[0]; L_pathfound:=true; While L_v[] Begin ok:=true; x:=0; While (x0) and (b10) and (l1>0) then Begin L_p1[y]:=x; L_nhan[y]:=false; L_e[y]:=L_min(L_e[x],l1); L_v:=L_v+[y]; L_v1:=L_v1+[y]; If y=L_G1.sodinh-1 then Begin exit; End; End; End; End; L_pathfound:=false; end; procedure L_Inc_flow(var L_G1:L_typedothi); { tang luong theo duong tang } var x,y,t,t1:integer; tang,a,k:real; s,s1,s2,s3,s4:string; ok:boolean; begin x:=L_G1.sodinh-1; y:=L_G1.sodinh-1; tang:=L_e[L_G1.sodinh-1]; ok:=false; while x0 begin y:=L_p1[x]; 164 L_giatri(L_G1,x,y,t,a,L_b); {a:=c[x,y],b:=f[x,y]} L_giatri(L_G1,y,x,t1,k,L_l); {k:=c[y,x],l:=f[y,x]} if L_nhan[x] then L_G1.dscanh[t1].trongso.gia:=L_G1.dscanh[t1].trongso.gia+tang else begin L_G1.dscanh[t].trongso.gia:=L_G1.dscanh[t].trongso.gia-tang; ok:=true; end; x:=y; end; end; procedure L_luongcucdai(L_G:L_typedothi; var L_G1:L_typedothi;var gt:real); { thu tuc the hien thuat toan Ford_fulkerson } var x,y,z,t,i,j,t1,t2:integer; a1,b1,f:real; ok1,stop:boolean; s,s1,ch,ch1,a:string; begin L_G1.SoDinh:=L_G.SoDinh ; L_G1.socanh:=L_G.socanh; setlength(L_p1,L_G1.SoDinh); setlength(L_nhan,L_G1.SoDinh ); setlength(L_e,L_G1.SoDinh ); setlength(L_G1.DSdinh,L_G1.SoDinh ); Setlength(L_G1.dscanh,L_G1.SoCanh ); for j:=0 to L_G.SoDinh -1 L_G1.DSDinh[j]:=L_G.DSDinh[j]; for j:=0 to L_G.SoCanh -1 L_G1.DSCanh[j]:=L_G.DSCanh[j]; stop:=false; while not stop begin L_find_path(L_G1); if L_pathfound then begin tam:=tam+1; if tam>1 then 165 L_inc_flow(L_G1) else stop:=true; end; f:=0; for y:= to L_G1.sodinh-1 begin L_giatri(L_G1,0,y,t1,a1,b1); f:=f+b1; end; for y:=0 to L_G1.Socanh -1 if L_G1.DSCanh[y].DinhCuoi =L_G1.SoDinh -1 then begin break; end; tam:=0; t2:=1; while (t2

Ngày đăng: 25/07/2023, 16:12

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan