Thuật toán Ford-Fulkerson (L.R.Ford & D.R.Fulkerso n 1962)

Một phần của tài liệu Hướng dẫn tìm hiểu lý thuyết đồ thị trên máy tính (Trang 61 - 64)

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]). Quy ước rằng nếu Trace[B] = 0 tức là không tồn tại đường đi từ A tới B, sau đó tăng luồng dọc theo đường tăng luồng nếu tìm thấy.

program Max_Flow_by_Ford_Fulkerson;

const max = 50; maxReal = 1E9;

var c, f: array[1..max, 1..max] of Real; Trace: array[1..max] of ShortInt;

Delta: array[1..max] of Real; n, A, B: Byte;

(*procedure Enter; Như trên*)

function Min(X, Y: Real): Real;begin if X < Y then Min := X else Min := Y;end;function FindPath: Boolean;

var

u, v: Byte;

Queue: array[1..max] of Byte; First, Last: Byte;

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ỉ là để nó khác 0 mà thôi, số dương nào chẳng được}

Delta[A] := maxReal; {Khởi tạo nh∙n}

repeat

u := Queue[First]; Inc(First); for v := 1 to n do

if Trace[v] = 0 then {Xét nhứng đỉnh v chưa đánh dấu}

begin

if (c[u, v] > 0) and (f[u, v] < c[u, v]) then {Nếu (u, v) là cung thuận trên Gf}

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]); {c[u, v] - f[u, v] là trọng số cung (u, v)}

end else

if (c[v, u] > 0) and (f[v, u] > 0) then {Nếu (u, v) là cung nghịch trên Gf}

begin

Trace[v] := -u; {Lưu vết, Trace[v] mang dấu âm}

Delta[v] := min(Delta[u], f[v, u]); {f[v, u] là trọng số cung nghịch (u, v) trên Gf}

end; (adsbygoogle = window.adsbygoogle || []).push({});

if Trace[B] <> 0 then {Nếu đ∙ đánh dấu được B thì việc tìm đường thành công, thoát ngay}

begin

FindPath := True; Exit; end;

if Trace[v] <> 0 then {Trace[v] khác 0 tức là từ u có thể thăm v, thì đưa v vào Queue}

begin

Inc(Last);

Queue[Last] := v; 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

u, v: ShortInt; 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); 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 đó.

Đị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.

Bài tập: (adsbygoogle = window.adsbygoogle || []).push({});

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 đượ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.

Đ10. Bài toán tìm cặp ghép cực đại trên đồ thị hai phía

Một phần của tài liệu Hướng dẫn tìm hiểu lý thuyết đồ thị trên máy tính (Trang 61 - 64)