Luận văn tốt nghiệp
42
Chương 4
ĐƯỜNG ĐI NGẮN NHẤT TRONG ĐỒ THỊ
Giới thiệu:
Trong các ứng dụng thực tế bài toán tìm đường đi ngắn nhất giữa hai đỉnh của
một đồ thị liên thông có ý nghĩa rất lớn. Bài toán tìm đường đi ngắn nhất được
ứng dụng trong thực tế như để chọn một hành trình tiết kiệm nhất (về thời gian
hoặc chi phí) trên một mạng giao thông đường thuỷ, đường bộ hoặc đường
không. Bài toán lập l
ịch thi công các công đoạn trong một công trình thi công
lớn. Bài toán lựa chọn đường truyền tin với chi phí nhỏ nhất trong mạng thông
tin... Dùng thuật giải đường đi ngắn nhất trong đồ thị giải quyết bài toán sửa gói
tin sai trong việc truyền tin... dưới đây ta xét một số thuật toán để tìm đường đi
ngắn nhất trong đồ thị có trọng số và đồ thị không có trọng số.
I. ĐƯỜNG ĐI NGẮN NHẤ
T TRONG ĐỒ THỊ KHÔNG CÓ TRỌNG SỐ
1. Định nghĩa: Đồ thị không có trọng số là đồ thị hữu hạn trên các cạnh
không có trọng số. Bài toán tìm đường đi ngắn nhất giữa hai đỉnh a,b trong đồ
thị không có trọng số
G = <X, U>
là tìm đường đi giữa hai đỉnh a, b sao cho có
số các cạnh (cung) là ít nhất.
2. Thuật toán:
Bước 1: Tại đỉnh a ta ghi số 0
Các đỉnh có cạnh đi từ đỉnh a đến ta ghi số 1.
Giả sử ta đã ghi tới i, tức là ta đã đánh số được các tập đỉnh là A(0) = {a}, A(1),
A(2), ... , A(i) trong đó A(i) là tập tất cả các đỉnh được ghi bởi số i. Ta xác định
tập đỉnh được đánh số bởi số i + 1 là A(i+1) = {x / x
X, x
A(k) với k = 0,
...,i và tồn tại y
A(i) sao cho từ y có cạnh (cung) tới x}. Do tính hữu hạn của
đồ thị, sau một số hữu hạn các bước, thuật toán dừng lại và cho kết quả là tập
các đỉnh có chứa b được đánh số bởi m là A(m).
Bước 2: Do bước 1 thì đỉnh b được đánh số bởi m, điều này chứng tỏ đường đi
từ a đến b có m cạnh (cung) và là đường ngắn nhất đi từ a đến b. Để tìm t
ất cả
các đường có độ dài m ngắn nhất đi từ a đến b, ta xuất phát từ b đi ngược về a
theo đúng nguyên tắc sau đây:
Luận văn tốt nghiệp
43
- Tìm tất cả các đỉnh có cạnh (cung) tới b được ghi số m - 1, giả sử đó là x
ik
(k
= 1, 2,...).
- Với mỗi đỉnh x
ik
tìm tất cả các đỉnh có cạnh (cung) với x
ik
(k = 1, 2, ...) được
ghi số m -2.
Bằng cách lùi dần trở lại, đến một lúc nào đó gặp đỉnh ghi số 0, đó chính là đỉnh
a. Tất cả các đường xác định theo các bước trên là đường đi từ a đến b có độ dài
ngắn nhất là m cần tìm.
Hình 1.1
Ví dụ đồ thị như hình 1.1 xây dựng đường đi ngắn nhất theo thuật toán trên:
Bước 1: Đỉnh a được đánh số 0 và có A(0) = {a}
A(1) = {x
1
, x
6
, x
7
}
A(2) = {x
2
, x
5
, x
8
}
A(3) = {x
3
, b, x
9
}
Bước 2: Từ bước 1 ta có b
A(3) nên từ a đến b là đường đi ngắn nhất có 3
cung. Tiếp theo ta xác định tất cả các đường đi ngắn nhất có độ dài 3:
Đỉnh có cung về b được đánh số 2 là x
5
Đỉnh có cung tới x
5
được đánh số 1 là x
6
Đỉnh có cung về x
6
được đánh số 0 là a
Vậy đường cần tìm là a - x
6
- x
5
- b.
II. ĐƯỜNG ĐI NGẮN NHẤT TRONG ĐỒ THỊ CÓ TRỌNG SỐ
1. Các khái niệm
Cho đồ thị hữu hạn
G = <X, U>
với mỗi cạnh u
U ta đặt tương ứng với số
dương l(u) gọi là trọng số của u.
Đồ thị có cạnh như trên được gọi là đồ thị có trọng số.
Gọi
là một đường đi nào đó trong
G = <X, U>
Giả sử
= x
i
1
u
i
1
x
i
2
u
i
2
... x
i
n - 1
u
i
n-1
x
i
n
, x
ij
X , u
ij
U (j = 1, 2, ...,n).
Khi đó ký hiệu gọi là trọng số của đường
∑
−
=
1
)()(
n
j
ij
ull
α
x
1
x
2
x
3
x
4
x
7
x
8
x
9
x
10
x
6
x
5
b
a
0
1
2 3
3
3
2
1
1
2
Luận văn tốt nghiệp
44
Ta ký hiệu D(a,b) là tập tất cả các đường đi nối đỉnh a với đỉnh b trong đồ thị
G.
Đường đi
giữa a và b là ngắn nhất nếu
thoả mãn l(
) = min {l(
) /
D(a,b)}
Bài toán: Cho đơn đồ thị G = <X, U> liên thông có trọng số, và a, b
X. Tìm
các đường đi ngắn nhất giữa 2 đỉnh a, b.
2. Thuật toán tìm đường đi ngắn nhất cho đồ thị có trọng số
2.1 Cơ sở thuật toán tìm đường đi ngắn nhất
Cho G = <X, U> tìm đường đi ngắn nhất từ đỉnh a tới đỉnh b
Với x
X nếu độ dài đường đi từ đỉnh xuất phát tới đỉnh x có trọng số là l(
)
thì
(x) = l(
) gọi là trọng số của đỉnh x. Cơ sở của tất cả các thuật toán tìm
đường đi ngắn nhất là xác định được các trọng số nhỏ nhất cho tất cả các đỉnh từ
đó tìm đường đi ngắn nhất.
Bước 1: Đánh trọng số các đỉnh, trọng số của đỉnh xuất phát là
(a) = 0.
Tại các đỉnh còn lại ta ghi một số dương nào đó sao cho nó đủ lớn hơn trọng số
của các đỉnh từ a tới.
Bước 2: Thực hiện việc giảm trọng số các đỉnh. Giả sử tại đỉnh x được ghi trọng
số
(x). Nếu tồn tại đỉnh y có trọng số
(y) từ y sang x mà
(x) >
(y) + l(y, x)
thì ta thay trọng số của
(x) bởi trọng số
'(x) =
(y) + l(y, x). Trường hợp
(x) <
(y) + l(y, x), trọng số của x giữ nguyên là
(x). Quá trình thực hiện cho
tới khi trọng số của tất cả các đỉnh trong G = <X, U> đạt cực tiểu, tức là x
X
không tồn tại y
X kề với x mà
(y) + l(y, x) <
(x).
Bước 3: Xác định đường từ a đến b có trọng số ít nhất.
Từ bước 3 ta xác định được trọng số của đỉnh b. Xuất phát từ b đi về đỉnh kề với
b, chẳng hạn đó là đỉnh x
i
n
có tính chất
(b) =
(x) + l(x
i
n
, b). Nếu không có
đỉnh kề với x
i
n
như vậy thì ta đi về đỉnh kề với b có trọng số cạnh (cung) từ đỉnh
đó về b là ít nhất.
Từ đỉnh x
i
n
ta đi ngược về đỉnh x
i
n-1
có tính chất
(x
i
n
) =
(
i
n-1
) + l(x
i
n-1
, x
i
n
)
nếu không đi về đỉnh kề với x
i
n
mà trọng số cạnh (cung) giữa chúng là ít nhất.
Bằng cách đó ta sẽ đi về đỉnh x
i
1
mà đỉnh kề là a sao cho
(x
i
1
) =
(a) + l(a,
x
i
1
) = l(a, x
i
1
) với
(a) = 0.
Đường
= ax
i
1
x
i
2
... x
i
n - 1
x
i
n
b là đường đi từ a đến b có trọng số ít nhất trong
số tất cả các đường từ a đến b.
Thật vậy l(
) = l(a,x
i
1
) + l(x
i
1
,x
i
2
) + ... + l(x
i
n-1
,x
i
n
) + l(x
i
n
,b) = [
(x
i
1
)-
(a)] +
[
(x
i
2
) -
(x
i
1
)] + ...
+ [
(x
i
n
) -
(x
i
n-1
)] + [
(b) -
(x
i
n
)] =
(b) (1)
Giả sử
D(a, b) là 1 đường bất kỳ từ a đến b và có dạng:
Luận văn tốt nghiệp
45
= a
j
1
x
j
2
... x
j
k-1
x
j
k
b. Theo bước 2 ta có bất đẳng thức sau:
l(a, x
j
1
)
(x
j
1
) -
(a) =
(x
j
1
)
l(x
j
1
, x
j
2
)
(x
j
2
) -
(x
j
1
)
.....................................
l(x
j
k-1
,x
j
k
)
(x
j
k
) -
(x
j
k-1
)
l(x
j
k
, b)
(b) -
(x
j
k
)
Cộng 2 vế ta có:
l(
) = l(a, x
j
1
) + l(x
j
1
, x
j
2
) + ... + l(x
j
n-1
, x
j
k
) + l(x
j
k
, b)
(b) (2)
So sánh (1) và (2) ta có:
l(
) = min{ l(
) /
D(a, b)}
2.2 Thuật toán Dijkstra
Có thể khái quát thuật toán bằng thủ tục sau:
Procedure Dijikstra(G: đồ thị liên thông có trọng số dương)}
{G: có các đỉnh a = v
0
, v
1
, ..., v
n
= b và trọng số l(v
i
, v
j
) =
nếu (v
i
, v
j
)
U của G}
For i:=1 to n
(v
i
) :=
;
(a) := 0;
S :=
{ban đầu các trọng số được khởi tạo sao cho trọng số của a = 0, còn các đỉnh
khác bằng
,
tập S rỗng}
While b
S Begin
u:= đỉnh không thuộc S có
(u)
nhỏ nhất;
S := S
{u};
For tất cả các đỉnh v không thuộc S
if (u) + l(u,v) < (v) then (v) := (u) + l(u,v)
{thêm vào S đỉnh có trọng số nhỏ nhất và sửa đổi trọng số của các đỉnh
không thuộc S}
End;
{l(
) = l(a, b) = độ dài đường đi ngắn nhất từ a đến b}
Độ phức tạp của thuật toán là O(n
2
), tức là phải dùng O(n
2
) phép cộng và so
sánh đường đi ngắn nhất giữa 2 đỉnh trong đồ thị đơn vô hướng liên thông có
trọng số.
2.3 Thuật toán Ford - Bellman
Luận văn tốt nghiệp
46
Khác với thuật toán Dijkstra xác định các trọng số bé nhất của tất cả các đỉnh
bằng cách "nổi bọt" dần các trọng số bé nhất, mỗi lần trọng số bé nhất được tìm
thấy thì lấy nó làm hạt nhân để điều chỉnh và xác lập các trọng số cho các đỉnh
khác, còn thuật toán Ford - Bellman xác định các trọng số nhỏ nhất cho tất cả
các đỉnh bằng cách duyệt tất cả các đỉnh, tr
ọng số nhỏ nhất của một đỉnh được
xác lập là sau một số lần hữu hạn điều chỉnh nhờ các vòng lặp.
Thuật toán được mô tả bằng thủ tục sau:
Procedure Ford_Bellman;
{Input: Đồ thị có hướng G = <X, U> n đỉnh, a
X là đỉnh xuất phát.
t(i, j) với i, j
X là ma trận trọng số
Output: Với x
X tìm các (x)
bé nhất và Truoc(x) để ghi nhận đỉnh đi trước x
trong các đường đi ngắn nhất từ a đến x.
}
Begin
{Khởi tạo}
For x
X do Begin
(x) := t[a, x];
Truoc[x] := a;
End;
(a) := 0;
For k:=1 to n - 2 do
For x
X \ {a} do
For y
X do
if (x) > (y) + t[y, x] then begin
(x) := (y) + t[y, x];
Truoc(x) := y;
End;
End;
Độ phức tạp của thuật toán là O(n
3
) chúng ta có thể chấm dứt vòng lặp theo k
khi phát hiện trong quá trình thực hiện 2 vòng lặp trong không có biến d[u] nào
bị thay đổi giá trị. Đối với những đồ thị có số cạnh m thoả mãn m < 6.n thì tốt
hơn là sử dụng danh sách kề để biểu diễn đồ thị, khi đó vòng lặp theo y cần viết
dưới dạng
For tất cả các đỉnh y kề với x do
if (x) > (y) + t[y, x] then begin
(x) := (y) + t[y, x];