Mỗi đỉnh v được gán nhãn (Trace[v], Delta[v]). Trong đó Trace[v] là đỉnh liền trước v trong đường đi từ A tới v, Trace[v] âm hay dương tuỳ theo (Trace[v], v) là cung nghịch hay cung thuận trên đồ thị tăng luồng, Delta[v] là trọng số nhỏ nhất của các cung trên đường đi từ A tới v trên đồ thị tăng luồng.
Bước lặp sẽ tìm đường đi từ A tới B trên đồ thị tăng luồng đồng thời tính luôn các nhãn (Trace[v], Delta[v]). Sau đó tăng luồng dọc theo đường tăng luồng nếu tìm thấy.
PROG10_2.PAS Thuật toán Ford-Fulkerson
program Max_Flow_by_Ford_Fulkerson; const
max = 100; maxC = 10000; var
c, f: array[1..max, 1..max] of Integer; Trace: array[1..max] of Integer;
Delta: array[1..max] of Integer; n, A, B: Integer;
(* procedure Enter; Như trên*)
function Min(X, Y: Integer): Integer; begin
if X < Y then Min := X else Min := Y; end;
function FindPath: Boolean; var
u, v: Integer;
Queue: array[1..max] of Integer; First, Last: Integer;
begin
FillChar(Trace, SizeOf(Trace), 0); {Trace[v] = 0 đồng nghĩa với v chưa đánh dấu}
First := 1; Last := 1; Queue[1] := A;
Trace[A] := n + 1; {Chỉ cần nó khác 0 để đánh dấu mà thôi, số dương nào cũng được cả}
Delta[A] := maxC; {Khởi tạo nhãn}
repeat
u := Queue[First]; Inc(First); {Lấy u khỏi Queue}
if Trace[v] = 0 then {Xét nhứng đỉnh v chưa đánh dấu thăm}
begin
if f[u, v] < c[u, v] then {Nếu (u, v) là cung thuận trên Gf và có trọng số là c[u, v] - f[u, v]}
begin
Trace[v] := u; {Lưu vết, Trace[v] mang dấu dương}
Delta[v] := min(Delta[u], c[u, v] - f[u, v]); end
else
if f[v, u] > 0 then {Nếu (u, v) là cung nghịch trên Gf và có trọng số là f[v, u]}
begin
Trace[v] := -u; {Lưu vết, Trace[v] mang dấu âm}
Delta[v] := min(Delta[u], f[v, u]); end;
if Trace[v] <> 0 then {Trace[v] khác 0 tức là từ u có thể thăm v}
begin
if v = B then {Có đường tăng luồng từ A tới B}
begin
FindPath := True; Exit; end;
Inc(Last); Queue[Last] := v;{Đưa v vào Queue}
end; end;
until First > Last; {Hàng đợi Queue rỗng}
FindPath := False; {ở trên không Exit được tức là không có đường}
end;
procedure IncFlow; {Tăng luồng dọc đường tăng luồng} var
IncValue, u, v: Integer; begin
IncValue := Delta[B]; {Nhãn Delta[B] chính là trọng số nhỏ nhất trên các cung của đường tăng luồng}
v := B; {Truy vết đường đi, tăng luồng dọc theo đường đi}
repeat
u := Trace[v]; {Xét cung (u, v) trên đường tăng luồng}
if u > 0 then f[u, v] := f[u, v] + IncValue {(u, v) là cung thuận thì tăng f[u, v]}
else begin u := -u;
f[v, u] := f[v, u] - IncValue; {(u, v) là cung nghịch thì giảm f[v, u]}
end; v := u; until v = A; end;
(* procedure PrintResult; Như trên*) begin
Enter;
FillChar(f, SizeOf(f), 0); {Khởi tạo luồng 0}
repeat
if not FindPath then Break; IncFlow;
until False; PrintResult; end.
Định lý về luồng cực đại trong mạng và lát cắt hẹp nhất:
Luồng cực đại trong mạng bằng khả năng thông qua của lát cắt hẹp nhất. Khi đã tìm được luồng cực đại thì theo thuật toán trên sẽ không có đường đi từ A tới B trên đồ thị tăng luồng. Nếu đặt tập X gồm những đỉnh đến được từ đỉnh phát A trên đồ thị tăng luồng (tất nhiên A∈X) và tập Y gồm
những đỉnh còn lại (tất nhiên B∈Y) thì (X, Y) là lát cắt hẹp nhất đó. Có thể có nhiều lát cắt hẹp nhất, ví dụ nếu đặt tập Y gồm những đỉnh đến được đỉnh thu B trên đồ thị tăng luồng (tất nhiên B∈
Y) và tập X gồm những đỉnh còn lại thì (X, Y) cũng là một lát cắt hẹp nhất.
Định lý về tính nguyên:
Nếu tất cả các khả năng thông qua là số nguyên thì thuật toán trên luôn tìm được luồng cực đại với luồng trên cung là các số nguyên. Điều này có thể chứng minh rất dễ bởi ban đầu khởi tạo luồng 0 thì tức các luồng trên cung là nguyên. Mỗi lần tăng luồng lên một lượng bằng trọng số nhỏ nhất trên các cung của đường tăng luồng cũng là số nguyên nên cuối cùng luồng cực đại tất sẽ phải có luồng trên các cung là nguyên.
Định lý về chi phí thời gian thực hiện giải thuật:
Trong phương pháp Ford-Fulkerson, nếu dùng đường đi ngắn nhất (qua ít cạnh nhất) từ đỉnh phát tới đỉnh thu trên đồ thị tăng luồng thì cần ít hơn n.m lần chọn đường đi để tìm ra luồng cực đại. Edmonds và Karp đã chứng minh tính chất này và đề nghị một phương pháp cải tiến: Tại mỗi bước, ta nên tìm đường tăng luồng sao cho giá trị tăng luồng được gia tăng nhiều nhất.
Nói chung đối với thuật toán Ford-Fulkerson, các đánh giá lý thuyết bị lệch rất nhiều so với thực tế, mặc dù với sự phân tích trong trường hợp xấu, chi phí thời gian thực hiện của thuật toán là khá lớn. Nhưng trên thực tế thì thuật toán này hoạt động rất nhanh và hiệu quả.
Bài tập:
1. Cho một mạng gồm n đỉnh với p điểm phát A1, A2, ..., Ap và q điểm thu B1, B2, ..., Bq. Mỗi cung của mạng được gán khả năng thông qua là số nguyên. Các đỉnh phát chỉ có cung đi ra và các đỉnh thu chỉ có cung đi vào. Một luồng trên mạng này là một phép gán cho mỗi cung một số thực gọi là luồng trên cung đó không vượt quá khả năng thông qua và thoả mãn với mỗi đỉnh không phải đỉnh phát hay đỉnh thu thì tổng luồng đi vào bằng tổng luồng đi ra. Giá trị luồng bằng tổng luồng đi ra từ các đỉnh phát = tổng luồng đi vào các đỉnh thu. Hãy tìm luồng cực đại trên mạng.
2. Cho một mạng với đỉnh phát A và đỉnh thu B. Mỗi cung (u, v) được gán khả năng thông qua c[u, v]. Mỗi đỉnh v khác với A và B được gán khả năng thông qua d[v]. Một luồng trên mạng được định nghĩa như trước và thêm điều kiện: tổng luồng đi vào đỉnh v không được vượt quá khả năng thông qua d[v] của đỉnh đó. Hãy tìm luồng cực đại trên mạng.
3. Cho một đồ thị liên thông gồm n đỉnh và m cạnh, hãy tìm cách bỏ đi một số ít nhất các cạnh để làm cho đồ thị mất đi tính liên thông
§11. BÀI TOÁN TÌM BỘ GHÉP CỰC ĐẠI TRÊN ĐỒ THỊ HAI PHÍA