Tải bản đầy đủ (.doc) (31 trang)

BÁO CÁO BÀI TOÁN LUỒNG CỰC ĐẠI TRÊN MẠNG potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (388.57 KB, 31 trang )

TRƯỜNG ĐẠI HỌC TÂY ĐÔ
KHOA: KỸ THUẬT-CÔNG NGHỆ
LỚP: CAO ĐẲNG TIN HỌC 4
NHÓM: 14
Thành Viên:
1. Nguyễn Trường An
2. Nguyễn Nhật Minh
3. Nguyễn Hoàng Đăng
4. Cái Văn Nam
5. Võ Trường Giang
BÁO CÁO BÀI TOÁN LUỒNG CỰC
ĐẠI TRÊN MẠNG
Nội Dung Chính Gồm 2 Phần:
Phần 1: TRÊN PƯƠNG DIỆN CỦA MÔN TOÁN RỜI
RẠC

1 . Luồng vận tải:
1.1. Định nghĩa: Mạng vận tải là một đồ thị có hướng, không có
khuyên và có trọng số G=(V,E) với V={v
0
, v
1
, ,v
n
}thoảmãn:
1) Mỗi cung e ∈ E có trọng số m(e) là một số nguyên không âm
và được gọi là khả năng thông qua của cung e.
2) Có một và chỉ một đỉnh v
0
không có cung đi vào, tức là
deg


t
(v
0
)=0. Đỉnh v
0
được gọi là lối vào hay đỉnh phát của mạng.
3) Có một và chỉ một đỉnh v
n
không có cung đi ra, tức là
deg
o
(v
n
)=0. Đỉnh v
n
được gọi là lối ra hay đỉnh thu của mạng.
1.2. Định nghĩa: Để định lượng khai thác, tức là 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 ra
khái niệm luồng vận tải và nó được định nghĩa như sau.
1
Hàm ϕ xác định trên tập cung E và nhận giá trị nguyên được
gọi là luồng vận tải của mạng vận tải G nếu ϕ thoả mãn:
1) ϕ(e) ≥ 0, ∀e ∈ E.
2)


Γ∈ )(
)(
ve
e

ϕ
=

+
Γ∈ )(
)(
ve
e
ϕ
, ∀v ∈V, v≠v
0
, v≠v
n
. Ở đây,

Γ
(v)={e∈E | e
có đỉnh cuối là v},
+
Γ
(v)={e∈E | e có đỉnh đầu là v}.
3) ϕ(e) ≤ m(e), ∀e ∈ E.
Ta xem ϕ(e) như là lượng hàng chuyển trên cung e=(u,v)
từ đỉnh u đến đỉnh v và không vượt quá khả năng thông qua
của cung này. Ngoài ra, từ điều kiện 2) ta thấy rằng nếu v
không phải là lối vào v
0
hay lối ra v
n
, thì lượng hàng chuyển tới

v bằng lượng hàng chuyển khỏi v.
Từ quan hệ 2) suy ra:
4)

+
Γ∈ )(
0
)(
ve
e
ϕ
=


Γ∈ )(
)(
n
ve
e
ϕ
=:
n
v
ϕ
.
Đại lượng
n
v
ϕ
(ta còn ký hiệu là

n
ϕ
) được gọi là luồng qua
mạng, hay cường độ luồng tại điểm v
n
hay giá trị của luồng ϕ.
Bài toán đặt ra ở đây là tìm ϕ để
n
v
ϕ
đạt giá trị lớn nhất, tức là
tìm giá trị lớn nhất của luồng.
1.3. Định nghĩa: Cho mạng vận tải G=(V,E) và 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)=

∈Me
e)(
ϕ
được
gọi là luồng của tập cung M.
Từ điều kiện 2) dễ dàng suy ra hệ quả sau.
1.4 . Hệ quả: Cho ϕ là luồng của mạng vận tải G=(V,E) và A ⊂
V \{v
0

,v
n
}. Khi đó:
ϕ(

Γ
(A))=ϕ(
+
Γ
(A)).
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
n
v
ϕ
max trên mạng G.
Nguyên lý của các thuật toán giải bài toán tìm luồng cực
đại là như sau.
2
2.1. Định nghĩa: Cho A ⊂ V là tập con tuỳ ý không chứa lối vào
v
0
và chứa lối ra v
n
. Tập

Γ
(A) được gọi là một thiết diện của
mạng vận tải G.
Đại lượng m(


Γ
(A))=


Γ∈ )(
)(
Ae
em
được gọi là khả năng thông
qua của thiết diện

Γ
(A).
Từ định nghĩa thiết diện và khả năng thông qua của nó ta
nhận thấy rằng: mỗi đơn vị hàng hoá được chuyển từ v
0
đến v
n

ít nhất cũng phải một lần qua một cung nào đó của thiết diện

Γ
(A). Vì vậy, dù luồng ϕ và thiết diện

Γ
(A) như thế nào đi
nữa cũng vẫn thoả mãn quan hệ:
ϕ
n

≤ m(

Γ
(A)).
Do đó, nếu đối với luồng ϕ và thiết diện W mà có:
ϕ
n
= m(W)
thì chắc chắn rằng luồng ϕ đạt giá trị lớn nhất và thiết diện W
có khả năng thông qua nhỏ nhất.
2.2. Định nghĩa: Cung e trong mạng vận tải G với luồng vận tải
ϕ được goi là cung bão hoà nếu ϕ(e)=m(e).
Luồng ϕ của mạng vận tải G được gọi là luồng đầy nếu
mỗi đường đi từ v
0
đến v
n
đều chứa ít nhất một cung bão hoà.
Từ định nghĩa trên ta thấy rằng, nếu luồng ϕ trong mạng
vận tải G chưa đầy thì nhất định tìm được đường đi α từ lối
vào v
0
đến lối ra v
n
không chứa cung bão hoà. Khi đó ta nâng
luồng ϕ thành ϕ’ như sau:





∈+
=
.)(
,1)(
)('
αϕ
αϕ
ϕ
ekhie
ekhie
e
Khi đó ϕ’ cũng là một luồng, mà giá trị của nó là:
ϕ’
n
= ϕ
n
+1 > ϕ
n
.
Như vậy, đối với mỗi luồng không đầy ta có thể nâng giá
trị của nó và nâng cho tới khi nhận được một luồng đầy.
Tuy vậy, thực tế cho thấy rằng có thể có một luồng đầy,
nhưng vẫn chưa đạt tới giá trị cực đại. Bởi vậy, cần phải dùng
thuật toán Ford-Fulkerson để tìm giá trị cực đại của luồng.
2.3. Thuật toán Ford-Fulkerson:
3
Để tìm luồng cực đại của mạng vận tải G, ta xuất phát từ luồng
tuỳ ý ϕ của G, rồi nâng luồng lên đầy, sau đó áp dụng thuật
toán Ford-Fulkerson hoặc ta có thể áp dụng thuật toán Ford-
Fulkerson trực tiếp đối với luồng ϕ.

Thuật toán gồm 3 bước:
Bước 1 (đánh dấu ở đỉnh của mạng): Lối vào v
0
được đánh dấu
bằng 0.
1) Nếu đỉnh v
i
đã được đánh dấu thì ta dùng chỉ số +i để đánh
dấu cho mọi đỉnh y chưa được đánh dấu mà (v
i
,y)∈E và cung
này chưa bão hoà (ϕ(v
i
,y)<m(v
i
,y)).
2) Nếu đỉnh v
i
đã được đánh dấu thì ta dùng chỉ số −i để đánh
dấu cho mọi đỉnh z chưa được đánh dấu mà (z,v
i
)∈E và luồng
của cung này dương (ϕ(z,v
i
)>0).
Nếu với phương pháp này ta đánh dấu được tới lối ra v
n

thì trong G tồn tại giữa v
0

và v
n
một xích α, mọi đỉnh đều khác
nhau và được đánh dấu theo chỉ số của đỉnh liền trước nó (chỉ
sai khác nhau về dấu). Khi đó chắc chắn ta nâng được giá trị
của luồng.
Bước 2 (nâng giá trị của luồng): Để nâng giá trị của luồng ϕ, ta
đặt:
ϕ’(e) = ϕ(e), nếu e∉α,
ϕ’(e) = ϕ(e)+1, nếu e∈α được định hướng theo chiều của xích
α đi từ v
o
đến v
n
,
ϕ’(e) = ϕ(e)−1, nếu e∈α được định hướng ngược với chiều của
xích α đi từ v
o
đến v
n
.
0
e
+i
y v
j
z
v
n
v

i
v
0
-j
4
ϕ’ thoả mãn các điều kiện về luồng, nên ϕ’ là một luồng và ta
có:
ϕ’
n
= ϕ
n
+1.
Như vậy, ta đã nâng được luồng lên một đơn vị.
Sau đó lặp lại một vòng mới. Vì khả năng thông qua của
các cung đều hữu hạn, nên quá trình phải dừng lại sau một số
hữu hạn bước.
Bước 3: Nếu với luồng ϕ
0
bằng phương pháp trên ta không thể
nâng giá trị của luồng lên nữa, nghĩa là ta không thể đánh dấu
được đỉnh v
n
, thì ta nói rằng quá trình nâng luồng kết thúc và
ϕ
0
đã đạt giá trị cực đại, đồng thời gọi ϕ
0
là luồng kết thúc.
Khi mạng vận tải G=(V,E) đạt tới luồng ϕ
0

, thì bước tiếp
theo ta không thể đánh dấu được tới lối ra v
n
. Trên cơ sở hiện
trạng được đánh dấu tại bước này, ta sẽ chứng minh rằng
luồng ϕ
0
đã đạt được giá trị cực đại.
2.4. Bổ đề: Cho luồng ϕ của mạng vận tải G=(V,E) và A ⊂ V,
chứa lối ra v
n
và không chứa lối vào v
0
. Khi đó:
))(())(( AA
n
v
+−
Γ−Γ=
ϕϕϕ
.
Chứng minh: Đặt A
1
=A \{v
n
}. Theo Hệ quả 1.4, ta có:
))(())((
11
AA
+−

Γ=Γ
ϕϕ
(1).
Đặt C
1
={(a,v
n
)∈E | a∉A}. Khi đó
∪Γ=Γ
−−
)()(
1
AA
C
1

∩Γ

)(
1
A
C
1
= ∅, nên
ϕϕϕ
+Γ=Γ
−−
))(())((
1
AA

(C
1
) (2).
Đặt C
2
={(b,v
n
)∈E | b∈A
1
}. Khi đó C
2
={(b,v
n
)∈E | b∈A},
∪Γ=Γ
++
)()(
1
AA
C
2

∩Γ
+
)(A
C
2
= ∅, nên
ϕϕϕ
−Γ=Γ

++
))(())((
1
AA
(C
2
) (3).
5
Ngoài ra,
)(
n
v

Γ
= C
1
∪C
2
và C
1
∩C
2
= ∅, nên
n
v
ϕ
=
))((
n
v


Γ
ϕ
=
ϕ
(C
1
)+
ϕ
(C
2
) (4).
Từ (1), (2), (3) và (4), ta có:
))(())(( AA
n
v
+−
Γ−Γ=
ϕϕϕ
.
2.5. Định lý (Ford-Fulkerson): Trong mạng vận tải G=(V,E), giá
trị lớn nhất của luồng bằng khả năng thông qua nhỏ nhất của
thiết diện, nghĩa là
))((minmax
,,
0
Am
AvAvVA
v
n

n

∈∉⊂
Γ=
ϕ
ϕ
.
Chứng minh: Giả sử trong mạng vận tải G, ϕ
0
là luồng cuối
cùng, mà sau đó bằng phương pháp đánh dấu của thuật toán
Ford-Fulkerson không đạt tới lối ra v
n
. Trên cơ sở hiện trạng
được đánh dấu lần cuối cùng này, ta dùng B để ký hiệu tập
gồm các đỉnh của G không được đánh dấu. Khi đó v
0
∉B,
v
n
∈B. Do đó

Γ
(B) là một thiết diện của mạng vận tải G và
theo Bổ đề 2.4, ta có:
))(())((
000
BB
n
v

+−
Γ−Γ=
ϕϕϕ
(1).
Đối với mỗi cung e=(u,v)∈

Γ
(B) thì u∉B và v∈B, tức là u
được đánh dấu và v không được đánh dấu, nên theo nguyên
tắc đánh dấu thứ nhất, e đã là cung bão hoà:
ϕ
0
(e) = m(e).
Do đó,
))(()()())((
)()(
00
BmemeB
BeBe

Γ∈Γ∈

Γ===Γ
∑∑
−−
ϕϕ
(2).
Đối với mỗi cung e=(s,t)∈
+
Γ

(B) thì s∈B và t∉B, tức là s
không được đánh dấu và t được đánh dấu, nên theo nguyên tắc
đánh dấu thứ hai:
ϕ
0
(e) = 0.
Do đó,
0)())((
)(
00
==Γ

+
Γ∈
+
Be
eB
ϕϕ
(3).
Từ (1), (2) và (3) ta suy ra:
))((
0
Bm
n
v

Γ=
ϕ
.
6

Vì vậy,
0
n
v
ϕ
là giá trị lớn nhất của luồng đạt được, còn m(

Γ
(B)) là giá trị nhỏ nhất trong các khả năng thông qua của
các thiết diện thuộc mạng vận tải G.
Thí dụ 3: Cho mạng vận tải như hình dưới đây với khả năng
thông qua được đặt trong khuyên tròn, luồng được ghi trên các
cung. Tìm luồng cực đại của mạng này.
Luồng ϕ có đường đi (v
0
,v
4
), (v
4
,v
6
), (v
6
,v
8
) gồm các cung
chưa bão hoà nên nó chưa đầy. Do đó có thể nâng luồng của
các cung này lên một đơn vị, để được ϕ
1
.

Do mỗi đường xuất phát từ v
0
đến v
8
đều chứa ít nhất một
cung bão hoà, nên luồng ϕ
1
là luồng đầy. Song nó chưa phải là
luồng cực đại.
Áp dụng thuật toán Ford-Fulkerson để nâng luồng ϕ
1
.
6
11
6
3
4
2
3
2
2
4
6
5
5
7
v
1
v
5

v
2
v
3
v
4
v
6
v
7
v
0
v
8
4
4
4
4
4
4
4
4
3
8
5
5
8
6
12
9

ϕ
7
Xét xích α=(v
0
, v
4
, v
6
, v
3
, v
7
, v
8
). Quá trình đánh dấu từ v
0
đến
v
8
để có thể nâng luồng ϕ
1
lên một đơn vị bằng cách biến đổi
luồng tại các cung thuộc xích α được đánh dấu. Sau đó ta có
luồng ϕ
2
.
Xét xích β=(v
0
, v
1

, v
5
, v
2
, v
6
, v
3
, v
7
, v
8
). Quá trình đánh dấu từ v
0

đến v
8
để có thể nâng luồng ϕ
2
lên một đơn vị bằng cách biến
đổi luồng tại các cung thuộc xích β được đánh dấu. Sau đó ta
có luồng ϕ
3
.
6
+4
12
6
3
3

4
2
3
2
4
ϕ
1
+0
7
5
5
7
v
1
v
5
v
2
v
3
v
4
v
6
v
7
v
0
v
8

4
4
4
4
4
4
4
4
8
5
5
8
6
12
9
−6
+3
+7
+7
6+1
+3
2+1
−6
3−1
3+1
7+1
v
0
v
4

v
6
v
3
v
7
v
8
0
+0
+4
xích α
8
Tiếp theo ta chỉ có thể đánh dấu được đỉnh v
0
nên quá trình
nâng luồng kết thúc và ta được giá trị của luồng cực đại là:
3
8
v
ϕ
= 6+12+8 = 26.
Mặt khác, thiết diện nhỏ nhất

Γ
(B) với B={v
1
, v
2
, , v

8
} là
+7
6
12
7
+2
+1
3
4
3
2
3
2
ϕ
2
4
4
8
5
5
7
v
1
v
5
v
2
v
3

v
4
v
6
v
7
v
0
v
8
4
4
4
4
4
4
4
4
8
5
5
8
6
12
9
0
+0
−5
−6
+3

+7
7+1
+3
3+1
−6
2−1
+2
2+1
−5
3−1
+1
3+1
+0
7+1
0
v
0
v
1
v
2
v
6
v
3
v
8
v
5
v

7
xích β
8
12
6
4
4
2
3
4
1
4
4
8
5
5
8
v
1
v
5
v
2
v
3
v
4
v
6
v

7
v
0
v
8
4
4
4
4
4
4
4
4
8
5
5
8
6
12
9
ϕ
3
9

Γ
(B)={(v
0
,v
1
), (v

0
,v
2
), (v
0
,v
3
), (v
0
,v
4
)}.
Phần 2: TRÊN PHƯƠNG DIỆN CỦA MÔN CẤU TRÚC
DỮ LIỆU
1. Đặt vấn đề
Bài toán luồng cực đại trên mạng là một trong số những 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à giải quyết bởi hai nhà toán học Mỹ Ford và
Fulkerson vào đầu những năm 1950 và ngày càng được các nhà
khoa học quan tâm nghiên cứu. Hiện nay, mô hình xử lý song song
đã và đang phát triển mạnh mẽ giải quyết những vấn đề bế tắc mà
mô hình xử lý tuần tự gặp phải như vấn đề thời gian thực hiện
chương trình, tốc độ xử lý, khả năng lưu trữ của bộ nhớ, xử lý dữ
liệu với quy mô lớn
Trong bối cảnh đó, thuật toán tìm luồng cực đại cần được phát triển
theo hướng song song nhằm phát huy sức mạnh của bài toán.
2. Bài toán tìm luồng cực đại trên mạng
Cho mạng G(V,E,C), nguồn a, đích z. Trong số các luồng trên
mạng G, hãy tìm luồng có giá trị lớn nhất.

3. Ý tưởng thuật toán
Dựa trên thuật toán truyền thống và thuật toán hoán chuyển
nguồn đích, xây dựng thuật toán song song tìm luồng cực đại. Ý
tưởng của phương pháp này là thay vì trong thuật toán truyền thống
dùng một bộ vi xử lý thực hiện công việc tuần tự từ đỉnh nguồn đến
đỉnh đích. Trong thuật toán song song sử dụng hai bộ vi xử lý thực
hiện công việc song song, vi xử lý 1 xuất phát từ đỉnh nguồn, vi xử
lý 2 xuất phát từ đỉnh đích. Hai vi xử lý trong quá trình tìm đường
tăng luồng sẽ gặp nhau ở đỉnh trung gian t nào đó, công việc
tiếp theo vi xử lý 1 xử lý công việc từ đỉnh t đến nút nguồn, vi xử
lý 2 xử lý công việc từ đỉnh t đến nút đích.
4. Xây dựng thuật toán song song
10
 Đầu vào: Mạng
( )
EVG ,=
với nguồn a, đích z, khả năng thông
qua:
( )
( )
, ,
ij
C c i j G= ∈
.
Các đỉnh trong G được sắp xếp theo thứ tự nào đó.
 Đầu ra: Luồng cực đại
( )
( )
GjifF
ij

∈= ,,
.
 Các bước
Bước1: Khởi tạo
P1:
Luồng xuất phát: For i:= 1 to (n div 2) do
For j:= 1 to n do if c
ij
>0 then f
ij
=0
Đặt nhãn tiến
( )

cho đỉnh nguồn:
( )
∞↑ ,,
φ
a
Tạo lập tập S gồm các đỉnh đã có nhãn tiến nhưng chưa được
dùng để sinh nhãn tiến:
{ }
aS =:
; khởi gán điều kiện kết thúc
Stop:= False;
P2:
Luồng xuất phát: For i:= (n div 2)+1 to n do
For j:= 1 to n do if c
ij
>0 then f

ij
=0
Đặt nhãn lùi
( )

cho đỉnh đích:
( )
∞↓ ,,
φ
z
Tạo lập tập T gồm các đỉnh đã có nhãn lùi nhưng chưa được
dùng để sinh nhãn lùi:
{ }
zT =:
; khởi gán điều kiện tăng luồng:
inc_flow:= False;
Bước 2: Sinh nhãn
P1 Sinh nhãn tiến
Trường hợp Stop=True; thì xuất luồng cực đại, kết thúc.
Trường hợp inc_flow=True; chuyển sang thực hiện bước 3
2.1. Chọn đỉnh sinh nhãn tiến
* Trường hợp
φ
≠S
: Chọn đỉnh
S

u
nhỏ nhất (theo thứ tự).
Loại u khỏi S,

{ }
uSS \:=
. Ký hiệu nhãn tiến của u là
( )
α
,, p↑
và A là
tập các đỉnh chưa có nhãn tiến kề với đỉnh u, Sang bước 2.2.
* Trường hợp
φ
=S
, thì gán Stop:=True; thông báo hệ thống biết đã
gặp điều kiện dừng, xuất luồng cực đại, kết thúc.
2.2. Gán nhãn tiến cho đỉnh chưa có nhãn tiến và kề đỉnh sinh nhãn
tiến u.
Trường hợp Stop=True; thì xuất luồng cực đại, kết thúc.
11
Trường hợp inc_flow=True; chuyển sang thực hiện bước 3
* Trường hợp
φ
=A
: Quay lại bước 2.
* Trường hợp
φ
≠A
: Chọn
At

nhỏ nhất (theo thứ tự). Loại t
khỏi A,

{ }
tAA \:=
. Gán nhãn tiến cho t như sau:
Nếu
( )
Etu ∈,

utut
cf <
, đặt nhãn tiến đỉnh t là
{ }
( )
tutu
fcu
,,
,min,, −↑
α
.
Nếu
( )
Eut ∈,

tu
f 0>
, đặt nhãn tiến đỉnh t là
{ }
( )
tu
,u,minα,f↑
.

Nếu t không được gán nhãn tiến, thì quay lại bước 2.2.
Nếu t được gán nhãn tiến và t có nhãn lùi, thì gán inc_flow:=
True; thông báo cho hệ thống biết đã tìm được đường đi tăng
luồng, sang bước 3, hiệu chỉnh tăng luồng, xóa nhãn.
Nếu t được gán nhãn tiến và t không gán nhãn lùi, thì bổ sung
t vào S,
{ }
:S S t= ∪
và quay ngược lại bước 2.2.
P2: Sinh nhãn lùi
Trường hợp Stop=True; thì kết thúc.
Trường hợp inc_flow=True; chuyển sang thực hiện bước 3
2.3. Chọn đỉnh sinh nhãn lùi
* Trường hợp
φ
≠T
: Chọn đỉnh
Tv

nhỏ nhất (theo thứ tự).
Loại v khỏi T,
{ }
vTT \:=
.
Ký hiệu nhãn lùi của v là
( )
β
,,q↓
và B là tập các đỉnh chưa có
nhãn lùi kề đỉnh sinh nhãn lùi v.

Sang bước 2.4.
* Trường hợp
φ
=T
, thì Stop =True; thông báo hệ thống biết
P2 đã gặp điều kiện dừng, kết thúc.
2.4. Gán nhãn lùi cho đỉnh chưa có nhãn lùi và kề đỉnh sinh nhãn
lùi v.
Trường hợp Stop=True; thì kết thúc.
Trường hợp inc_flow=True; chuyển sang thực hiện bước 3
* Trường hợp
φ
=B
: Quay lại bước 2.
*Trường hợp
φ
≠B
: Chọn
Bt

nhỏ nhất (theo thứ tự). Loại t
khỏi B.
{ }
tBB \:=
gán nhãn lùi cho t như sau:
Nếu
( )
Evt ∈,

tvtv

cf <
, đặt nhãn lùi đỉnh t là
{ }
( )
tvtv
fcv −↓ ,min,,
β
.
Nếu
( )
Etv ∈,

0>
vt
f
, đặt nhãn lùi đỉnh t là
{ }
( )
vt
fv ,min,,
β

.
Nếu t không được gán nhãn lùi, thì quay lại bước 2.4.
12
Nếu t được gán nhãn lùi và t có nhãn tiến thì gán inc_flow:=
True; thông báo cho hệ thống biết P2 đã tìm được đường đi tăng
luồng, sang bước 3, hiệu chỉnh tăng luồng, xóa nhãn.
Nếu t được gán nhãn lùi và t không có nhãn tiến, thì bổ sung t
vào T,

{ }
tTT ∪=:
và quay lại bước 2.4.
Bước 3: Hiệu chỉnh tăng luồng, xóa nhãn
Ta có t là đỉnh được gán nhãn tiến ở bước 2.2 hoặc nhãn lùi ở
bước 2.4 để thuật toán dẫn đến bước 3. Đỉnh t có nhãn tiến
( )
α
,, p↑

và nhãn lùi
( )
β
,,q↓
. Đặt
{ }
βαδ
,min=
.
Ta hiệu chỉnh luồng f và xóa nhãn như sau.
P 1
3.1. Hiệu chỉnh ngược từ t về a theo nhãn tiến
3.1.1. Khởi tạo
pitj == :,:
3.1.2. Hiệu chỉnh
Nếu cung
( )
Gji ∈,
, thì hiệu chỉnh
δ

+=
ijij
ff
.
Nếu cung
( )
Gij ∈,
, thì hiệu chỉnh
δ
−=
ijij
ff
.
3.1.3. Tịnh tiến
Nếu
ai =
, thì xóa tất cả các nhãn tiến trên mạng trừ đỉnh
nguồn a và đỉnh đích z, thông báo hệ thông biết P1 đã thực hiện
việc tăng luồng, xoá nhãn tiến xong, đợi P2 xoá nhãn xong, quay
lại bước 2.
Nếu
ai ≠
, thì đặt
ij =:

hi
=
:
, với h là thành phần thứ hai của
nhãn tiến đỉnh j. Sau đó quay lại bước 3.1.2.

P 2
3.2. Hiệu chỉnh từ t đến z theo nhãn lùi
3.2.1. Khởi tạo
qjti == :,:
3.2.2. Hiệu chỉnh
Nếu cung
( )
Gji ∈,
, thì hiệu chỉnh
δ
+=
ijij
ff
.
Nếu cung
( )
Gij ∈,
, thì hiệu chỉnh
δ
−=
ijij
ff
.
3.2.3. Tịnh tiến
Nếu
zi =
, thì xóa tất cả các nhãn lùi trên mạng trừ đỉnh nguồn a và
đỉnh đích z, thông báo hệ thống biết P2 đã thực hiện việc tăng
luồng, xoá nhãn lùi xong, đợi P1 xoá nhãn xong, quay lại bước 2.
13

Nếu
zi ≠
, thì đặt
ji =:

kj =:
, với k là thành phần thứ hai của
nhãn lùi đỉnh i. Sau đó quay lại bước 3.2.2.
Sơ đồ mô tả thuật toán cho ở hình 1.
VÍ DỤ THUẬT TOÁN
Ví dụ sau đây cho thấy những bước ban đầu của thuật toán Ford-
Fulkerson trong một mạng vận tải gồm 4 nút, nguồn A và thoát D.
Các đường đi tăng được tìm bằng phương pháp tìm kiếm theo
14
chiều sâu, trong đó các đỉnh lân cận được duyệt theo thứ tự bảng
chữ cái. Ví dụ này cho thấy biểu hiện của trường hợp xấu nhất của
thuật toán. Mỗi bước chỉ gửi thêm được một luồng giá trị 1 qua
mạng. Nếu sử dụng phép tìm theo chiều rộng thay vì theo chiều
sâu, ta sẽ chỉ cần hai bước
Đường
đi
Khả năng thông qua Mạng đạt được
Mạng vận tải ban đầu
A,B,C,D
min(c
f
(A,B),c
f
(B,C),c
f

(C,D)) =
min(c(A,B) − f(A,B),c(B,C) −
f(B,C),c(C,D) − f(C,D)) =
min(1000 − 0,1 − 0,1000 − 0) = 1
A,C,B,D
min(c
f
(A,C),c
f
(C,B),c
f
(B,D)) =
min(c(A,C) − f(A,C),c(C,B) −
f(C,B),c(B,D) − f(B,D)) =
min(1000 − 0,0 − ( − 1),1000 − 0) = 1
Mạng vận tải cuối cùng
VÍ DỤ CHỨNG MINH KHI TA CÀI ĐẶT TRÊN
MÁY:
#include<iostream>
#include<deque>
#define nm 1001
15
using namespace std;
typedef struct node *ptr;
struct node{int data,cost;ptr pnext;};
void chen(ptr &f,int v,int c)
{
ptr p=new node;
p->data=v;
p->cost=c;

p->pnext=f;
f=p;
}
ptr a[nm];
int c[nm][nm];
int f[nm][nm];
int trace[nm];
int n,m,t,s,k;
int u,v;
int res=0;
deque<int>q;
bool findpath()
{
q.clear();
memset(trace,0,sizeof(trace));
q.push_back(s);
trace[s]=n+1;
while (q.size())
{
int u=q.front();q.pop_front();
ptr p=a[u];
while (p)
{
int v=p->data;
if (!trace[v]&&c[u][v]>f[u][v])
{
trace[v]=u;
16
if (v==t)return true;
q.push_back(v);

}
p=p->pnext;
}
}
return false;
}
void incflow()
{
int u,v,delta=1000000000;
v=t;
while (v!=s)
{
u=trace[v];
delta=min(delta,c[u][v]-f[u][v]);
v=u;
}
v=t;
while (v!=s)
{
u=trace[v];
f[u][v]+=delta;
f[v][u]-=delta;
v=u;
}
}
int main()
{
scanf ("%d%d%d%d",&n,&m,&s,&t);
for (int i=1;i<=m;i++)
{

scanf ("%d%d%d",&u,&v,&k);
c[u][v]=k;
chen(a[u],v,k);
17
}
while (1)
{
if (!findpath())break;
incflow();
}
for (int v=1;v<=n;v++)
if (f[s][v]>0)res+=f[s][v];
printf ("%d",res);
getch();
return 0;
}
MỘT VÍ DỤ KHÁC VỚI SỰ TƯỜNG MINH VỀ BÀI TOÁN:
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 thí
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 xe đông nhất và chúng tạo thành chỗ hẹp tương ứng của
dòng giao thông xét theo hai nút đã chọn. Một thí 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 các đ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ác ống.
Cần phải tìm luồng dầu lớn nhất có thể bơm dầu từ tàu chở
dầu vào bể chứa.
Định lý: 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 đó.
18
(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 và t

X*.).
Định lý trên 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 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:
Bước lặp tăng luồng (Ford – Fulkerson): Tìm đườ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ể tìm theo thủ
tục mô tả trong việc chứng minh định lý trên. Thuật toán Ford-
Fulkerson được mô tả trong thủ tục sau đây:
Procedure Luongcucdai;
Begin
Stop := false;
While not Stop do
If < Tìm đườ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ứ
19
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.
20
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;
V
T
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] :=
+∞
;
V
T
:= {s};
Pathfound := true;
While V
T
<> {} do
BEGIN
u

V
T
;( * lấy u từ V
T
*)
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] };
V
T
:=V
T

{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
P[v] := u ;

ε
[v] := min {
ε
[u] , f[u,v] };
V
T
:=V
T


{v};(* nạp v vào danh sách các đỉnh có nhãn *)
if v = t then exit;
21
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 }
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
begin
find_path;
If pathfound then
Inc_flow
Else
22
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à (V
T
, V\ V
T
) >
End;
Chương trình sau là chương trình phục vụ cho việc học tập và
giảng dạy về bài toán tìm luồng cực đại trong mạng. Chương trình
sau được xây dựng bằ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 những chức năng sau:
* Tóm tắt thuật toán Ford – Fulkeson.
* Hiển thị các bước thực hiện ứng với từng ví dụ cụ thể
Tóm tắt thuật toán Ford – Fulkerson :
Chức năng này có mục đích giúp cho người sử dụng nắm
vững được thuật toán trước khi đi vào các thí dụ cụ thể.
Hiển thị các bước thực hiện của bài toán:
Do chương trình nhằm mục đích phục vụ cho việc dạy và học
môn Toán rời rạc nên chức năng việc hiển thị chi tiết các bước giải
bài toán ứng với tưng thí dụ cụ thể giúp cho người sử dụng hiểu rõ
hơn về thuật toán.
Cấu trúc dữ liệu và cài đặt thuật toán:
Cấu trúc dữ liệu:
Đồ thị được lưu giữ dưới dạng tập đỉnh và tập
cạnh. Mỗi đỉnh được lưu theo cấu trúc của một
Record như sau:
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 là V
0
,V
1
,…)
23
- Biến ToaDo có kiểu L_TypeToaDo, lưu giữ toạ độ x, y

của mỗi đỉnh có cấu trúc của một Record như sau :
L_TypeToaDo = record
x,y:integer;
end;
Biến Muckichhoat có kiểu Byte lưu giữ mức độ kích hoạt của
đỉnh (mỗi đỉnh có 4 mức kích hoạt khác nhau), biến này dùng để
xác định đỉnh đầu, đỉnh cuối, đỉnh hẹp….
Tập cạnh của đồ thị cũng được lưu theo cấu trúc của Record,
cấu trúc của mỗi cạnh được lưu trữ như sau:
L_TypeCanh = record
DinhDau,DinhCuoi:Integer;
TrongSo:L_TypeChiphi;
end;
trong đó :
- Biến DinhDau có kiểu Integer, lưu giữ chỉ số đỉnh đầu của
cạnh .
- Biến DinhCuoi có kiểu Integer, lưu giữ chỉ số đỉnh cuối của
cạnh .
- Biến TrongSo có kiểu L_TypeChiPhi, lưu giữ giá và khả
năng thông qua của cạnh đang xét. Kiểu L_TypeChiPhi là
một Record có dạng như sau :
L_TypeChiPhi = record
Gia:real;
kntq:real;
end;
Cài đặt thuật toán:
Như đã trình bày ở phần trên , thuật toán Ford –Fulkerson
được cài đặt bằng cách kết hợp 2 thủ tục Find-Path (thủ tục gán
nhãn tìm đường tăng luồng) và Inc-Flow (thủ tục tăng luồng theo
đường tăng).

Đây là phần cài đặt chi tiết của thuật toán Ford – Fulkerson
(viết theo ngôn ngữ lập trình Delphi):
24
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 do
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<>[] do
Begin
ok:=true;
x:=0;
While (x<=L_G1.sodinh-1) and (ok=true) do
Begin
If x in L_v then ok:=false
Else
x:=x+1;

End;
L_v:=L_v-[x];
For y:=0 to L_G1.sodinh-1 do
If L_p1[y]=-1 then
Begin
L_giatri(L_G1,x,y,t,a1,b1); {a:=c[x,y],b:=f[x,y]}
L_giatri(L_G1,y,x,t1,k1,l1); {k:=c[y,x],l:=f[y,x]}
If (a1>0) and (b1<a1) then
Begin
25

×