Professional Documents
Culture Documents
Lê Duy Quang
Trang 1
BÀI TOÁN LUỒNG CỰC ĐẠI
b 2 c
3 4
a
2 z
5
4
d 2 e
Hình 1
Ta có khả năng thông qua cab = 3, cbc = 2, cad = 5, cdc = 2, cde = 2, ccz = 4, cez = 4.
1.2. Định nghĩa 2: luồng (hay luồng trong mạng)
Cho mạng G, với khả năng thông qua cij, (i,j) ∈ G. Tập các giá trị
{fij (i, j) ∈ G}
Gọi là luồng trên mạng G nếu thoã mãn
(i) 0 ≤ fij ≤ cij ∀ (i, j) ∈ G
(ii) Với mọi đỉnh k không phải là nguồn hoặc đích
∑
( i , k )∈G
f ik = ∑
( k , j )∈G
f kj
Lê Duy Quang
Trang 2
BÀI TOÁN LUỒNG CỰC ĐẠI
được biểu diễn bằng các số trong ngoặc đơn trong mạng
b 2(2) c
3(2) 4(3)
a
2(1) z
5(3)
4(2)
d 2(2) e
Hình 2
1.3. Định lý 1: Cho fij, (i,j)∈G, là luồng trên mạng G với nguồn a và đích z. Khi
đó:
∑
(a,i)∈G
f ai = ∑
( i, z )∈G
fiz
Chứng minh:
Gọi V là tập các đỉnh. Với các đỉnh i,j không kề nhau ta gán fij=0. Ta có
∑∑ f
j∈V i∈V
ai = ∑∑ fiz
j∈V i∈V
⇔ ∑ ∑ f ij − ∑ f ji = 0
j∈V i∈V i∈V
⇔ ∑ ∑ f − ∑ f
j∈V \{ a , z} i∈V
ij
i∈V
ji + ∑ f iz − ∑ f zi + ∑ fai − ∑ fai = 0
i∈V i∈V i∈V i∈V
⇔− ∑ f ai + ∑ fiz = 0
( a ,i ) ∈G ( i , z )∈G
⇔ ∑ f ai = ∑ fiz
( a ,i )∈G ( i , z )∈G
Lê Duy Quang
Trang 3
BÀI TOÁN LUỒNG CỰC ĐẠI
trên đường đi đó sao cho luồng mới có giá trị lớn hơn. Nếu không tìm được
đường đi như vậy thì ta có luồng cực đại.
Giả sử
P = (a, u, …, i, j, …, v, z)
là đường đi không có hướng từ a đến z.
Nếu cạnh (i, j) là cung trên P thì cung đó cùng hướng với P. Ngược lại
nếu (j, i) là cung thì cung đó ngược hướng với P.
Tập các cung cùng hướng với P kí hiệu là P+.
Tập các cung ngược hướng với P kí hiệu là P-.
Cơ sở của thuật giải là định lý sau.
2.1. Định lý 2: Cho f là luồng trên G. Giả sử
P = (a, u, …, i, j,…, v, z)
là đường đi không định hướng từ a đến z thoã
(i) Với mỗi cung (i, j) cùng hướng với P
fij < cij
(ii) Với mỗi cung (i, j) ngược hướng với P
0 < fij
Đặt
δ := min{x x∈ M}>0
Trong đó M là tập các giá trị cij –fij, (i, j)∈P+ và fij, (i, j)∈P-
Ta xây dựng luồng f’ như sau
fij ∀ (i, j) ∉ P
f := fij + δ ∀ (i, j) ∈ P+
'
ij
f ij − δ ∀ (i, j) ∈ P-
Khi đó luồng f’ có giá trị lớn hơn giá trị của luồng f một lượng là δ , tức
là
v(f’) = v(f) + δ
Chứng minh:
Theo cách xây dựng thì f’ thoã mãn các điều kiện của luồng. Cung (a, u)∈P, có
f'au = fau + δ
nên giá trị
v ( f ') = ∑
( a ,i )∈G
f ai' = ∑
( a ,i )∈G
fai + δ
Lê Duy Quang
Trang 4
BÀI TOÁN LUỒNG CỰC ĐẠI
Lê Duy Quang
Trang 5
BÀI TOÁN LUỒNG CỰC ĐẠI
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 2 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 theo cung này. Đầu tiên chỉ có đỉnh a đượ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ừ a ta gán cho tất cả các đỉnh kề với nó và nhãn của đỉnh a sẽ trở thành nhãn đã
xét. Tiếp theo, từ mỗi đỉnh v có nhãn chưa xét ta lại gán nhãn cho tất cả các
nhãn chưa có nhãn kề với nó và nhãn của đỉnh v trở thành nhãn đã xét. Quá trình
sẽ được lặp lại cho đến khi hoặc là đỉnh z 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 z vẫn chưa 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 đã là 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.
* Thuật toán Ford – Fulkerson:
Đầu vào: Mạng G với nguồn a, đích z, khả năng thông qua C = (cij), (i, j)∈G.
Ký hiệu a = v0, …, vn = z.
Đầu ra: Luồng cực đại F = (fij), (i, j)∈G.
Các bước:
(i) Khởi tạo luồng xuất phát: fij:=0 ∀(i, j)∈G.
(ii) Đặt nhãn cho nguồn: Cho nguồn a mang nhãn (,∞)
(iii) Kiểm tra nhãn của đích: nếu đích z có nhãn, sang bước (vi). Ngược lại
sang bước (iv).
(iv) Xác định đỉnh đánh dấu. Trong số các đỉnh mang nhãn và chưa được đánh
dấu chọn đỉnh vi với chỉ số I nhỏ nhất. Nếu không tồn tại đỉnh như vậy, kết thúc,
luồng F là cực đại. Ngược lại gán v:= vi và đánh dấu đỉnh v.
(v) Đặt nhãn các đỉnh chưa có nhãn kề đỉnh v: Giả sử (α ,∆ ) là nhãn đỉnh v.
Xét các cung có dạng (v,w), (w,v) theo thứ tự (v,v0), (v0,v), (v,v1),(v1,v)....trong
đó w chưa được mang nhãn.
Với cung dạng (v,w), nếu fvw < cvw, đặt nhãn đỉnh w là (v, min {∆ , cvw - fvw}),
nếu fvw = cvw , không đặt nhãn đỉnh w.
Với cung dạng (w, v), nếu fwv >0, đặt nhãn đỉnh w là (v, min {∆ , fwv}), nếu fwv =
0 , không đặt nhãn đỉnh w.
Sang bước (iii).
Lê Duy Quang
Trang 6
BÀI TOÁN LUỒNG CỰC ĐẠI
Lê Duy Quang
Trang 7
BÀI TOÁN LUỒNG CỰC ĐẠI
* Hai thủ tục Tìm đường tăng luồng và tăng luồng có thể mô tả bởi
chương trình như sau:
Procedure Find_Path;{ thủ tục gán nhãn tìm đường tăng luồng }
p[v], ε [v] là nhãn của đỉnh v;
VT – danh sách các đỉnh nhưng chưa xét;
c[u,v]- khả năng thông qua của cung (u,v),u,v ∈ V;
f[u,v]- luồng trên cung (u,v),(u,v ∈ V ) *)
begin
p[s]:=s; ε [s]:= +∞; VT= V\{s};
PathFound:=true;{Gán tìm thấy đường tăng luồng là đúng}
While VT≠ ∅ do
Begin
u<= VT; (* Lấy u từ VT *)
for v ∈ V\VT do
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 đỉnh có nhãn *)
If v=t then exit;
end;
if (c[v,u]>0) and (f[v,u]>0) then
begin
p[v]:= -u;
ε [v]:= min {ε [u],f[v,u]};
VT = VT ∪ {v}; (* Nạp v vào danh sách đỉnh có nhãn *)
If v=t then exit;
end;
end;
PathFound:= false;
end;
procedure Inc_Flow;{ Tăng luồng theo đường tăng }
begin
v:=p[t]; u:=t; tang:= ε [t];
while u ≠ s do
begin
if v>0 then f[v,u]:= f[v,u] + tang;
else
begin
v:= -v;
f[u,v]:= f[u,v] – tang;
end;
Lê Duy Quang
Trang 8
BÀI TOÁN LUỒNG CỰC ĐẠI
Lê Duy Quang
Trang 9
BÀI TOÁN LUỒNG CỰC ĐẠI
III./ Sơ đồ khối.
Sơ thuật toán Find_Path (Chi tiết) { Trả về TRUE nếu có đường tăng luồng }
P[t]:= s ; ε [t]:=
Begin +∞
VT = V\{s}
PathFound:= True
False
VT ≠ ∅
True
u ⇐ VT;
For v∈V\VT
False
C[u,v] >0 and
(F[u,v]<C[u,v])
True
P[v]:= u; ε [v]:=min{ε [u],C[u,v]-F[u,v]}
VT:= VT ∪ {v}
True
v= t End
False
False C[v,u]>0
and
F[v,u]>0
True
P[v]:= -u; ε [v]:= min{ε [u],F[v,u]}
VT:= VT ∪ {v}
True
v= t
False
Lê Duy Quang
Trang 10
BÀI TOÁN LUỒNG CỰC ĐẠI
Begin
False
End u≠ s
True
False True
v:= -v v>0 f[v,u]:=f[v,u] + tang
f[v,u]:=f[v,u] - tang
u:=v; v:=P[u]
Lê Duy Quang
Trang 11
BÀI TOÁN LUỒNG CỰC ĐẠI
Begin
Stop:= False
Tăng luồng
True
True
not Stop Find_Path Path-Found
False
False
Stop:= False
Mạng với luồng
cực đại
End
Lê Duy Quang
Trang 12
BÀI TOÁN LUỒNG CỰC ĐẠI
Lê Duy Quang
Trang 13
BÀI TOÁN LUỒNG CỰC ĐẠI
var
m, i, x, y: Integer;
fi: Text;
begin
Assign(fi, file_vao); reset(fi);
FillChar(c, SizeOf(c), 0);
Readln(fi, n, m, a, z);{số đỉnh, số cung, đỉnh nguồn, đỉnh thứ}
for i:=1 to m do
Readln(fi, x, y, c[x, y]);
Close(fi);
end;
{----------------------------------------------------------------------}
{Hàm tìm đường tăng luồng trên G, trả về True nếu tìm thấy}
{----------------------------------------------------------------------}
function FindPath: Boolean;
var
x, y: Integer;
hangdoi: array[1..max] of Integer; {Hàng đợi dùng cho BFS}
Truoc, Sau: Integer;
begin
FillChar(Nhan, SizeOf(Nhan), 0);{Đặt nhãn cho nguồn}
Truoc:= 1; Sau:= 1;
hangdoi[1]:= a;
Nhan[a]:= n + 1;{Nhãn=0 => y chưa thăm}
Repeat
x:= hangdoi[Truoc]; Inc(Truoc);{Lấy x khỏi hàng đợi}
for y:= 1 to n do
if (Nhan[y] = 0) and (c[x, y]>f^[x, y]) then {xét mọi y chưa thăm kề x trên
G}
begin
Nhan[y]:= x;
if y = z then {đến được z thì thuật toán dừng}
begin
Lê Duy Quang
Trang 14
BÀI TOÁN LUỒNG CỰC ĐẠI
Lê Duy Quang
Trang 15
BÀI TOÁN LUỒNG CỰC ĐẠI
var
x, y: Integer;
m: LongInt;
fo: Text;
begin
Assign(fo, file_ra); rewrite(fo);
m:= 0;
for x:=1 to n do
for y:= 1 to n do
if f^[x, y] > 0 then
begin
if x = a then m:= m + f^[a, y];
end;
writeln(fo,m:5);
for x:=1 to n do
begin
for y:= 1 to n do if f^[x, y]>0 then
begin
write(fo, x:5, y:5, f^[x, y]:10);
writeln(fo);
end;
end;
close(fo);
end;
{----------------------------------------------------------------------}
{CHƯƠNG TRÌNH CHÍNH}
{----------------------------------------------------------------------}
BEGIN
Nhapdulieu;
New(f);
FillChar(f^, SizeOf(f^), 0);
repeat
if not Findpath then Break;
Lê Duy Quang
Trang 16
BÀI TOÁN LUỒNG CỰC ĐẠI
Tangluong;
until False;
Duakqvaofile;
Dispose(f);{giải phóng bộ nhớ cấp cho f^};
END.
III/ Chức năng và giao diện chương trình:
III.1.Chức năng:
Sử dụng chương trình cài đặt thuật toán Ford – Fulkerson bằng pascal để
tìm luồng cực đại từ một mạng với dữ liệu cho trước chứa trong file text
“Fordfulk.inp”. Kết quả được chương trình tự động xử lý và in ra file text
“Fordfulk.out”
III.2.Giao diện:
Chương trình không có giao diện giao tiếp, các dữ liệu vào và ra có thể
nhập hoặc xem từ trong chương trình pascal, hoặc trên hệ điều hành windows.
Lê Duy Quang
Trang 17
BÀI TOÁN LUỒNG CỰC ĐẠI
6716
123 b 2 c
135 3 4
242 a
352 2 z
5
342 4
464
d 2 e
564
Hình 1
Lê Duy Quang
Trang 18
BÀI TOÁN LUỒNG CỰC ĐẠI
[2] Ebook Giải thuật và lập trình – Lê Minh Hoàng (ĐHSP Hà Nội)
[3] Nguyễn Đức Nghĩa - Nguyễn Tô Thành – Toán rời rạc – NXBGD. 1996
[4] Đinh Mạnh Tường - Đỗ Xuân Lôi - Cấu trúc dữ liệu và giải thuật –
NXBTK.1990
[5] Quách Tuấn Ngọc – Ngôn ngữ lập trình PASCAL – NXBGD.1985
[6] Trần Đức Huyên - Các thuật giải trong tin học – NXBGD.1991
Lê Duy Quang
Trang 19