Đường ựi ngắn nhất giữa tất cả các cặp ựỉnh

Một phần của tài liệu Giáo trình toán rời rạc 2 (Trang 75)

Rõ ràng ta có thể giải bài toán tìm ựường ựi ngắn nhất giữa tất cả các cặp ựỉnh của ựồ thị bằng cách sử dụng n lần thuật toán mô tả ở mục trước, trong ựó ta sẽ chọn s lần lượt là các ựỉnh của ựồ thị. Rõ ràng, khi ựó ta thu ựược thuật toán với ựộ phức tạp O(n4) (nếu sử dụng thuật toán Ford_Bellman) hoặc O(n3) ựối với trường hợp trọng số không âm hoặc ựồ thị không có chu trình. Trong trường hợp tổng quát, sử dụng thuật toán Ford_Bellman n lần không phải là cách làm tốt nhất. Ở ựây ta sẽ mô tả một thuật toán giải bài toán trên với ựộ phức tạp tắnh toán O(n3): thuật toán Floyd. Thuật toán ựược mô tả trong thủ tục sau ựây.

Procedure Floyd;

(* Tìm ựường ựi ngắn nhất giữa tất cả các cặp ựỉnh

đầu vào: đồ thị cho bởi ma trận trọng số a[i,j], i, j =1, 2,. . ,n. đầu ra:

Ma trận ựường ựi ngắn nhất giữa các cặp ựỉnh d[i,j]=, i,j = 1, 2. . .,n,

trong ựó d[i,j] cho ựộ dài ựường ựi ngắn nhất từ ựỉnh i ựến ựỉnh j. Ma trận ghi nhận ựường ựi

p[i,j], i, j = 1, 2.. . , n,

trong ựó p[i,j] ghi nhận ựỉnh ựi trước ựỉnh j trong ựường ựi ngắn nhất từ i ựến j. *) begin (* Khởi tạo *) for i:=1 to n do for j:=1 to n do begin d[i,j]:=a[i.j]; p[i.j]:=i;

end; (* Bước lặp *) for k:=1 to n do for i:=1 to n do for j:=1 to n do if d[i,j]>d[i,k]+d[k,j] then begin d[i,j]+d[i,k]+d[k,j]; p[i,j]>p[k,j]; end; end;

Rõ ràng ựộ phức tạp tắnh toán của thuật toán là O(n3). 11.3 Cài ựặt thuật toán Dijkstra

Thuật toán Dijkstra trên ngôn ngữ Pascal ựược trình bày một cách chi tiết trong bài 10 giáo trình bài tập

Bài 12 Bài toán luồng cực ựại trong mạng

Nhiều bài toán quy hoạch tuyến tắnh có thể quy về bài toán làm cực tiểu phắ tổn vận chuyển hàng trong một mạng (gồm các nút và các cung ựường) sao cho ựảm bảo ựược các nhu cầu ở một số nút khi ựã biết nguồng cung cấp tại một số nút khác. Các bài toán như vậy ựược gọi là các bài toán luồng trên mạng (network flow problem) hoặc bài toán chuyển vận (transshipment problem). đây là lớp bài toán quan trọng nhất và hay gặp nhất trong quy hoạch tuyến tắnh. Lớp này bao gồm các bài toán quen thuộc trong thực tế như: bài toán vận tải, các bài toán mạng ựiện và mạng giao thông, các bài toán quản lý và phân bổ vật tư, bài toán bổ nhiệm, bài toán kế hoạch tài chắnh, bài toán ựường ngắn nhất, bài toán luồng cực ựại Ầ

Bài toán luồng cực ựại trong mạng là một trong số bài toán tối ưu trên ựồ thị tìm ựược những ứng dụng rộng rãi trong thực tế cũng như những ứng dụng thú vị trong lý thuyết tổ hợp. Bài toán ựược ựề xuất vào ựầu năm 1950, và gắn liên với tên tuổi của hai nhà toán học Mỹ là Ford và Fulkerson. Trong chương này chúng ra sẽ trình bày thuật toán Ford và Fulkerson ựể giải bài toán ựặt ra và nêu một sô ứng dụng của bài toán.

12.1. Mạng. Luồng trong mạng. Bài toán luồng cực ựại

định nghĩa 12.1 Ta gọi mạng là ựồ thị có hướng G = (V,E), trong ựó duy nhất một ựỉnh s không có cung ựi vào gọi là ựỉnh phát, duy nhất một ựỉnh t không có cung ựi ra gọi là ựiểm thu và mỗi cung e=(v,w) ∈ E ựược gán với một số không âm c(e) =c(v,w) gọi là khả năng thông qua của cung e.

để thuận tiện cho việc trình bày ta sẽ qui ước rằng nếu không có cung (v,w) thì khả năng thông qua c(v,w) ựược gán bằng 0.

định nghĩa 12.2 Giả sử cho mạng G=(V,E). Ta gọi mạng f trong mạng G=(V,E) ;là ánh xạ f: ER+ gán cho mỗi cung e =(v,w) ∈ E một số thực không âm f(e)=f(v,w), gọi là luồng trên cung e, thoả mãn các ựiểu kiện sau:

- Luồng trên cung e ∈ E không vượt quá khả năng thông qua của nó: 0≤ f(e) ≤ c(e),

- điều kiện cân bằng luồng trên mỗi ựỉnh của mạng: Tổng luồng trên các cung ựi vào ựỉnh v bằng tổng luồng trên các cung ựi ra khỏi ựỉnh v, nếu v ≠ s, t:

Div f (v) = ∑ f(w,v) - ∑ f(v,w) = 0 w∈ N-(v) w ∈ N+(v)

trong ựo N-(v) Ờ tập các ựỉnh của mạng mà từ ựó có cung ựến v, N+(v) - tập các ựỉnh của mạng mà từ v có cung ựến nó:

N-(v) = { w ∈ V : (w,v) ∈ E } , N+(v) = { w ∈ V : (v,w) ∈ E } . Giá trị của luồng f là số

Val(f) = ∑ f(s,w ) = ∑ f(w,t). w∈ N+(s) w ∈ N-(t)

Bài toán luồng cực ựại trong mạng:

Cho mạng G(V,E). Hãy tìm luồng f* trong mạng với giá trị luồng val(f*) là lớn nhất. Luồng như vậy ta sẽ gọi là luồng cực ựại trong mạng.

Bài toán như vậy có thể xuất hiện trong rất nhiều ứng dụng thực tế. Chẳng hạn khi cần xác ựịnh cường ựộ lớn nhất của dòng vận tải giữa hai nút của một bản ựồ giao thông. Trong vắ dụ này lời giải của bài toán luồng cực ựại sẽ chỉ cho ta các ựoạn ựường ựông xe nhất và chúng tạo thành "chỗ hẹp" tương ứng với dòng giao thông xét theo hai nút ựược chọn. Một vắ dụ khác là nếu xét ựồ thị tương ứng với một hệ thống ựường ống dẫn dầu. Trong ựó các ống tương ứng với các cung, ựiểm phát có thể coi là tầu chở dầu, ựiểm thu là bể chứa, còn những ựiểm nối giữa các ống là các nút của ựồ thị. Khả năng thông qua của các cung tương ứng với tiết diện của các ống. Cần phải tìm luồng dầu lớn nhất có thể bơm từ tàu chở dầu vào bể chứa.

12.2. Lát cắt. ựường tăng luồng. định lý ford_fulkerson

định nghĩa 12.3. Ta gọi lát cắt (X, X*) là một cách phân hoạch tập ựỉnh V của mạng ra thành hai tập X và X* = V\X, trong ựó s∈ X, t ∈ X* . Khả năng thông qua của lát cắt (X, X*) là số

c(X,X*) = ∑c(v,w) v ∈ X w ∈ X*

Bổ ựề 12.1 Giá trị của luồng f trong mạng luôn nhỏ hơn hoặc bằng khả năng thông qua của lát cắt (X, X*) bất kỳ trong nó: val(f) ≤ c(X, X*).

Chứng minh. Cộng các ựiều kiện cân bằng luồng Divf(v)=0 với mọi v∈ X. Khi ựó ta có

∑ ( ∑ f(w,v ) - ∑ f(v,w) ) = -Val(f) v∈ X w∈ N-(v) w∈ N+(v)

tổng này sẽ gồm các số hạng dạng f(u,v) với dấu cộng hoặc dấu trừ mà trong ựó có ắt nhất một trong hai ựỉnh u,v phải thuộc tập X. Nếu cả hai ựỉnh u,v ựều trong tập X, thì f(u,v) xuất hiện với dấu cộng trong Divf(v) và với dấu trừ trong Divf(u), vì thế, chúng triệt tiêu lẫn nhau. Do ựó, sau khi giản ước các số hạng như vậy ở vế trái, ta thu ựược

- ∑ f(v,w) + ∑ f(v,w) = -val(f), v ∈ X v ∈ X* w∈ X* w∈ X hay là val(f) = ∑ f(v,w) - ∑ f(v,w) v ∈ X v ∈ X* w∈ X* w ∈ X Mặt khác, từ ựiều kiện 1 rõ ràng là ∑ f(v, w) ≤ ∑ c(v, w) v ∈ X v ∈ X* w∈ X* w∈ X còn - ∑ f(v,w) ≤ 0 v ∈ X* w∈ X suy ra val(f)≤c(X, X*). Bổ ựề ựược chứng minh.

Hệ quả 12.1 Giá trị luồng cực ựại trong mạng không vượt quá khả năng thông qua của lát cắt hẹp nhất trong mạng.

Ford và Fulkerson ựã chứng minh rằng giá trị luồng cực ựại trong mạng ựúng bằng khả năng thông qua của lát cắt hẹp nhất. để có thể phát biểu và chứng minh kết quả này chúng ra sẽ cần thêm một số khái niệm.

Giả sử f là một luồng trong mạng G = (V, E). Từ mạng G =(V, E) ta xây dựng ựồ thị có trọng số trên cung Gf = (V, Ef), với tập cung Ef và trọng số trên các cung ựược xác ựịnh theo qui tắc sau :

- Nếu e = (v,w) ∈ E với f(v,w) = 0, thì (v,w) ∈ Ef với trọng số c(v,w); - Nếu e = (v,w) ∈ E với f(v,w) =c(v,w), thì (w,v) ∈ Ef với trọng số f(v,w);

- Nếu e = (v,w) ∈ E với 0 < f(v,w) < c(v,w), thì (v,w) ∈ Ef với trọng số c(v,w) - f (v,w) và (w,v) ∈ Ef với trọng số f(v,w).

Các cung của Gf ựồng thời cũng là cung của G ựược gọi là cung thuận, các cung còn lại ựược gọi là cung nghịch. đồ thị Gf ựược gọi là ựồ thị tăng luồng.

Vắ dụ 12.1: Các số viết cạnh các cung của G ở Hình 12.1 theo thứ tự là khả năng thông qua và luồng trên cung.

Hình 12.1 Mạng G và luồng f. đồ thị có trọng số Gf tương ứng.

Giả sử P = (s = v0, v1, . . . , vk = t) là một ựường ựi từ s ựến t trên ựồ thị tăng luồng Gf. Gọi

ε là giá trị nhỏ nhất của các trọng số của các cung trên ựường ựi P. Xây dựng luồng fỖ trên mạng theo qui tắc sau:

f(u,v) + ε , nếu (u,v) ∈ P là cung thuận

fỖ(u,v) = f(u,v) - ε , nếu (v,u) ∈ P là cung nghịch

f(u,v), nếu (u,v) ∈ P

Dễ dàng kiểm tra ựược rằng fỖ ựược xây dựng như trên là luồng trong mạng và val(fỖ) = val(f) + ε . Ta sẽ gọi thủ tục biến ựổi luồng vừa nêu là tăng luồng dọc theo ựường P.

định nghĩa 12.4. Ta gọi ựường tăng luồng f là mọi ựường ựi từ s ựến t trên ựồ thị tăng luồng G(f).

định lý 12.1 Các mệnh ựề dưới ựây là tương ựương: (i) f là luồng cực ựại trong mạng; (ii) không tìm ựược ựường tăng luồng f;

(iii) val(f) = c(X,X*) với một lát cắt (X, X*) nào ựó.

Chứng minh.

(i) ⇒ (ii). Giả sử ngược lại, tìm ựược ựường tăng luồng P. Khi ựó ta có thể tăng giá trị luồng bằng cách tăng luồng dọc theo ựường P. điều ựó mâu thuẫn với tắnh cực ựại của luồng f.

(ii) ⇒ (iii). Giả sử không tìm ựược ựường tăng luồng. Ký hiệu X là tập tất cả các ựỉnh có thể ựến ựược từ ựỉnh s trong ựồ thị Gf, và ựặt X*=V\X. Khi ựó (X, X*) là lát cắt, và f(v,w) = 0 với mọi v ∈ X*, w ∈ X nên

val(f) = ∑ f(v,w) - ∑ f(v,w) = ∑ f(v,w) v ∈ X v ∈ X* v∈ X w∈ X* w∈ X w∈ X*

Với v ∈ X, w ∈ X*, do (v,w) ∈ Gf, nên f(v,w) = c(v,w). Vậy val(f) = ∑ f(v,w) = ∑ c(v,w) = c(X,X*)

v ∈ X v ∈ X w∈ X* w∈ X*

(iii) ⇒ (i). Theo bổ ựề 12.1, val(f) ≤ c(X,X*) với mọi luồng f và với mọi lát cắt (X,X*). Vì vậy, từ ựẳng thức val(f) = c(X,X*) suy ra luồng f là luồng cực ựại trong mạng. 12.3. Thuật toán tìm luồng cực ựại

định lý 12.1 là cơ sở ựể xây dựng thuật toán lặp sau ựây ựể tìm luồng cực ựại trong mạng: Bắt ựầu từ luồng với luồng trên tất cả các cung bằng 0 (ta sẽ gọi luồng như vậy là luồng không), và lặp lại bước lặp sau ựây cho ựến khi thu ựược luồng mà ựối với nó không còn ựường tăng:

Ý tưởng của thuật toán Ford Ờ Fulkerson 10 Xuất phát từ một luồng chấp nhận ựược f.

20 Tìm một ựường ựi tăng luồng P. Nếu không có thì thuật toán kết thúc. Nếu có, tiếp bước 3 dưới ựây.

30 Nếu δ(P) = +∞ thuật toán kết thúc.

Trong ựó δ(P) - Lượng luồng tăng thêm, hay nói khác là làm sự tăng luồng (flow

augmentation) dọc theo ựường ựi tăng luồng P một lượng thắch hợp mà các ràng buộc của bài toán vẫn thoả.

Cách tìm ựường ựi tăng luồng. Ta sử dụng thuật toán gán nhãn có nội dung như sau. Một ựường ựi P thoả mãn về ựường ựi tăng luồng, nhưng chỉ ựi từ s ựến k nào ựó (chưa tới t, nói chung) sẽ ựược gọi là ựường ựi chưa bão hoà (unsaturated path).

Ta nói ựỉnh u là ựã ựánh dấu (u is labeled) nếu ta biết là có một ựường ựi chưa bão hoà từ s tới u. Bây giờ ta sẽ xét tất cả các ựỉnh v có nối trực tiếp ựến ựỉnh u (sẽ gọi là ở cạnh ựỉnh u) xem chúng có thể ựược gán nhãn hay không khi u ựã gán nhãn. Việc này ựược gọi là thăm (scanning) ựỉnh u.

Nếu (u,v) có luồng trên cung F(u,v) < C(u,v) thì ta có thể nối thêm cung (u,v) và ựường ựi chưa bão hoà P từ s ựến u ựể ựược ựường ựi chưa bão hoà tới v. Vậy v có thể gán nhãn.

Bước lặp tăng luồng ( Ford - Fulkerson): Tìm dường tăng P ựối với luồng hiện có. Tăng luồng dọc theo ựường P.

Khi ựã có luồng cực ựại, lát cắt hẹp nhất có thể theo thủ tục mô tả trong chứng minh định lý 12.1. Sơ ựồ của thuật toán Ford-Fulkerson có thể mô tả trong thủ tục sau ựây:

Procedure Max_Flow;

(* Thuật toán Ford-Fulkerson *) Begin

(* Khởi tạo: Bắt ựầu từ luồng với giá trị 0 *) for u ∈ V do

for v ∈ V do f(u,v) := 0; stop := false;

while not stop do

if <Tìm ựược ựường tăng luồng P> then <Tăng luồng dọc theo P> else stop:=true;

End;

để tìm ựường tăng luồng trong G(f) có thể sử dụng thuật toán tìm kiếm theo chiều rộng (hay tìm kiếm theo chiều sâu), bắt ựầu từ ựỉnh s trong ựó 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 ựây ựể giải bài toán luồng cực ựại trong mạng. Thuật toán bắt ựầu từ luồng chấp nhận ựược nào ựó trong mạng (có thể bắt ựầu từ luồng không) , sau ựó ta sẽ tăng luồng bằng cách tìm các ựường tăng luồng. để tìm ựường tăng luồng ta sẽ áp dụng phương pháp gán nhãn cho các ựỉnh. Mỗi ựỉnh trong quá trình thực hiện thuật toán sẽ ở một trong ba trạng thái: chưa có nhãn, có nhãn chưa xét, có nhãn ựã xét. Nhãn của một ựỉnh v gồm hai phần và có một trong hai dạng sau : [+p v( ),ε( )v ] hoặc [−p v( ), ( )ε v ]. Phần thứ nhất +p(v) (-p(v)) chỉ ra là cần tăng giảm luồng theo cung (p(v),v)( cung (v, p(v)) còn phần thứ hai ε( )v chỉ ra lượng lớn nhất có thể tăng hoặc giảm luồng theo cung này. đầu tiên chỉ có ựỉnh s ựược khởi tạo nhãn và nhãn của nó là chưa xét, còn tất cả các ựỉnh còn lại ựều chưa có nhãn. Từ s ta gán nhãn cho tất cả các ựỉnh kề với nó và nhãn của ựỉnh s sẽ trở thành ựã xét. Tiếp theo, từ một ựỉnh v có nhãn chưa xét ta lại gán nhãn cho tất cả các ựỉnh chưa có nhãn kề với nó và nhãn của ựỉnh v trở thành ựã xét. Quá trình sẽ ựược lặp lại cho ựến khi hoặc là ựỉnh t trở thành có nhãn hoặc là nhãn của tất cả các ựỉnh có nhãn ựầu là ựã xét nhưng ựỉnh t vẫn

không có nhãn. Trong trường hợp thứ nhất ta tìm ựược ựường tăng luồng, còn trong

trường hợp thứ hai ựối với luồng ựang xét không tồn tại ựường tăng luồng (tức là luồng ựã cực ựại). Mỗi khi tìm ựược ựường tăng luồng, ta lại tăng luồng theo ựường tìm ựược, sau ựó xoá tất cả các nhãn và ựổi với luồng mới thu ựược lại sử dụng phép gán nhãn các ựỉnh ựể tìm ựường tăng luồng. Thuật toán sẽ kết thúc khi nào ựối với luồng ựang có trong mạng không tìm ựược ựường tăng luồng.

Trong ựó, thuật toán gán nhãn (The labeling algorithm) có thể ựược mô tả như sau: Gọi VT là tập mọi ựỉnh ựã gán nhãn nhưng chưa ựược thăm. Ta có thuật toán ựể tìm ựường ựi tăng luồng.

Xuất phát với VT = {s} và s là nút ựã ựánh dấu duy nhất. Một bước lặp sẽ có VT hiện hành và gồm ba bước như sau.

10 Nếu t ∈ VT hoặc VT = ∅, thuật toán kết thúc. Ngược lại thì chọn một ựỉnh u ∈ VT ựể thăm và ựưa nó ra khỏi VT. Xét tất cả các ựỉnh cạnh u, tức là xét mọi cung có dạng (u,v) và (v,u).

20 Nếu (u,v) ∈ E, F(u,v) < C(u,v) và v chưa gán nhãn thì gán nhãn nó và ựưa v vào tập VT.

30 Nếu (v,u) ∈ E, F(v,u) > 0 và v chưa gán nhãn thì gán nhãn nó và ựưa vào tập VT.

Bây giờ ta xét kết quả của thuật toán gán nhãn. Nó có kết thúc hữu hạn hay không? Nhận xét rằng một ựỉnh ựược vào tập VT chỉ khi chuyển từ chưa gán nhãn. Do ựó một ựỉnh chỉ ựược vào VT nhiều nhất là một lần. Mà mỗi bước lặp bỏ một ựỉnh ra khỏi VT. Do ựó, vì số ựỉnh của mạng là hữu hạn, thuật toán phải kết thúc hữu hạn.

Hai thủ tục tìm ựường tăng luồng có thể mô tả như sau : Procedure Find-path;

{ Thủ tục gán nhãn ựường tăng luồng p[v], ∈ε[v] là nhãn của ựỉnh v;

VT là danh sách các ựỉnh có nhãn chưa xét ;

c[u,v] là khả năng thông qua của cung (u,v),u,v ∈V; f[u,v] là luồng trên cung (u,v), (u,v ∈ V); }

BEGIN p[s] := s ; ε[s] :=+∞; VT := {s}; Pathfound := true; While VT <> {} do BEGIN u ⇐ VT ; ( * lấy u từ VT *) For v∈V do 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] := min {ε[u],c[u,v]-f[u,v] }; VT:=VT∪{v}; (* nạp v vào danh sách các ựỉnh có nhãn *) If v = t then exit; End Else

If (c[v,u] > 0) and (f[v,u] < 0) then Begin

ε[v] := min {ε[u] , f[u,v] }; VT:=VT∪{v};(* nạp v vào danh sách các ựỉ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 do

begin v := p[u];

if v > 0 then f[v,u] := f[v,u] + tang else

begin v := -v;

f[u,v] :=f[u,v] Ờtang; end;

u := v ; end;

Procedure FF;

{ thủ tục thể hiện thuật toán Ford_fulkerson }

(* khởi tạo bắt ựầu từ luồng với giá trị 0 *)

For u ∈ V do

For v ∈ V do f[u,v] :=0; Stop := false;

While not Stop do begin find_path; If pathfound then Inc_flow Else Stop:=true; End;

< Luồng cực ựại trong mạng là f[u,v], u,v ∈ V > < Lát cắt hẹp nhất là (VT , V\ VT) >

End;

Ta xét vắ dụ sau ựể làm quen với thuật toán Ford-Fullkerson

Vắ dụ 12.2 Áp dụng thuật toán Ford-Fullkerson tìm luồng cực ựại bằng cách gán nhãn cho ựỉnh của mạng G với luồng f ựược cho như Hình 12.2, hai số viết bên cạnh mỗi cung là khả năng thông qua và luồng của các cung. Kết quả các bước của thuật toán mô tả bởi các ựồ thị và bảng dưới ựây. Mạng với luồng cực ựại thu ựược ở Hình 12.3. Lát cắt bé nhất là X = {s,c}, X*= {b,d,e,t} và giá trị luồng cực ựại là 12.

Hình 12.2 Mạng G và minh họa từng bước thuật toán Ford-Fullkerson

Một phần của tài liệu Giáo trình toán rời rạc 2 (Trang 75)

Tải bản đầy đủ (PDF)

(137 trang)