You are on page 1of 40

ĐƯỜNG ĐI NGẮN NHẤT

TOÁN RỜI RẠC - MI3010


Nội dung
• Bài toán
• Thuật toán
• Ford-Bellman
• Dijkstra
• Floyd
1. Bài toán

3
a. Bài toán
• Cho G = (V, E). Mỗi cạnh của đồ thị được gán với một số thực
gọi là trọng số.
• Bài toán: s và t là 2 đỉnh của đồ thị G . Hãy tìm đường đi từ s
đến t có tổng trọng số nhỏ nhất.
B
5
5
A 15 G

3
22 3
11
7 C
E F 9
16
Đường đi ngắn nhất từ A đến D?
4
D
Ma trận trọng số
• Xét đồ thị G = (V, E) với tập đỉnh V = {v1, …, vn}. Mỗi cạnh của
đồ thị được gán với một số thực gọi là trọng số
• Ma trận kề của đồ thị là ma trận Anxn xác định như sau:
0 nếu vi vj ∉ E
aij = ൝
c nếu vi vj ∈ E, trọng số bằng c

5
b. Điều kiện để bài toán có lời giải
• Tồn tại đường đi từ s tới t
• Đồ thị vô hướng liên thông hoặc đồ thị có hướng liên thông mạnh
• Đồ thị vô hướng, trong đó s, t thuộc một thành phần liên thông
• Đồ thị có hướng có đường đi từ s tới t
• Đồ thị không chứa chu trình âm
• Đồ thị vô hướng không có cạnh âm
• Đồ thị có hướng không có chu trình âm

6
Ví dụ
• Ví dụ: đường đi ngắn nhất từ A đến C?

B
5
5
A 15 G
3
22 3
7 -5
C
E F
16 9
D

7
Ví dụ
• Ví dụ: đường đi ngắn nhất từ A đến C?
B
5
5
A 15 G 3

22 3
-5
7 C
E F
16 9
D

8
c. Ý tưởng
• Nếu s, u2, …, uk-1, v, uk+1, …, un-1, t là đường đi ngắn nhất từ s
→ t thì:
• s, u2, …, uk-1, v là đường đi ngắn nhất từ s → v
• v, uk+1, …, un-1, t là đường đi ngắn nhất từ v → t
s v
… … t
X

⇒ mở rộng thành bài toán tìm đường đi ngắn nhất từ một đỉnh
đến tất cả các đỉnh còn lại

9
Ý tưởng
• Tại đỉnh cần xét, ta thử đường đi qua các đỉnh trung gian để
đến đích theo các chiến lược khác nhau.
• Cập nhật đường đi ngắn nhất nếu tìm được đường đi tốt hơn
đường đi tốt nhất đã biết.
• Thông tin cần lưu:
• Độ dài đường đi ngắn nhất từ s → v đã biết
• Đỉnh nằm trước v trên đường đi ngắn nhất đã biết.

10
Thuật toán

11
1. Thuật toán Ford-Bellman
Thuật toán Ford-Bellman
// Khởi tạo
for v  V do{
d[v]:= a[s,v]; // khoảng cách từ s → v
π[v]:= s; // đỉnh trước v trên đường đi là s
}
d[s]:= 0;
// Lặp
for k:= 1 to |V|-2 do
for v  V\{s} do
for u  V\{s} do //đỉnh trung gian
if d[v] > d[u] + a[u,v] then{
d[v]:= d[u] + a[u,v];
Thêm các đỉnh trung gian vào đường
π[v]:= u;
đi từ s đến v
} Số đỉnh trung gian không quá n-2
13
Ví dụ: đường đi min từ z
Đồ thị: u v
5
 
–2
6 –3
8
z 0 7
–4
7 2
 
9
x y

14
Ví dụ u
6
5
v

• Khởi tạo –2
6 –3
8
z 0 7
–4
7 2
7 
9
x y
k d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z

15
Ví dụ u v
5
 i=1 6 4
Đến u v y x
–2
Qua 6 –3
u 6, z 11, u 2, u 7, z 8
v ∞6, z 11, u 2, u 7, z z 0 7
–4
y ∞6, z 11, u 2, u 7, z 7 2
x ∞6, z 4, x 2, u 7, z 7 2
9
x y
k d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z
1 0; z 6; z 4; x 2; u 7; z

16
Thuật toán Ford-Bellman
// Khởi tạo
……
d[s]:= 0;
// Lặp
for k:= 1 to |V|-2 do
for (u,v)  E do
if d[v] > d[u] + a[u,v] then{
d[v]:= d[u] + a[u,v];
π[v]:= u;
}
Kiểm tra xem đường đi đến v có chứa (u,v)?

17
Ví dụ: đường đi min từ z
u v
(k = 1) 5
6 
z-u, 6: 6 = 6 –2
6 –3
z-x, 7: 7 = 7
8
u-v, 5: d[v] = 6+5=11, π[v] = u z 0 7
–4
u-x, 8: 7<6+8 7 2

u-y, -4: d[y] = 6-4 = 2, π[y] = u 7


9

v-u, -2: 6 < 11 -2 x y

x-v, -3: d[v] = 7-3 = 4, π[v] = x


x-y, 9: 2<7+9 k d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
y-z, 2: 0 = 0 0; z 6; z ∞; z ∞; z 7; z
y-v, 7: 4<2+7 1 0; z 6; z 4; x 2; u 7;z

18
Kiểm tra chu trình âm
for (u,v)  E do
if d[v] > d[u] + a[u,v] then {
d[v] = -∞
π[v] = u
}

19
Ví dụ
• Tìm đường đi ngắn nhất từ đỉnh A đến các đỉnh còn lại trên đồ
thị có trọng số sau:
1
A B
3
5
3
-1
-1 C
F 2 1

-2
1
E 4 D
Nhận xét
• Thuật toán Ford-Bellman áp dụng được cho trường hợp không
có chu trình âm trong đồ thị
• Nhược điểm:
• Chi phí tính toán lớn
• Không thể cải tiến cho trường hợp tổng quát
• Các vòng lặp thường hội tụ về kết quả sớm hơn so với điều kiện dừng
vòng lặp
• Nếu đồ thị không có cạnh âm thì: giá trị nhỏ nhất của d[i] trên
mỗi hàng của ma trận F-B sẽ không thể nhỏ hơn tính từ hàng
đó về sau
21
2. Thuật toán Dijkstra
Thuật toán Dijsktra
• Ý tưởng:
• Do đồ thị không có cạnh âm: trong mỗi bước, đỉnh có khoảng cách
nhỏ nhất (d[v] min) sẽ không thay đổi về sau
• Chọn đỉnh này là đỉnh trung gian đi đến các đỉnh còn lại sẽ giúp đường
đi có khả năng tối ưu cao hơn

23
Thuật toán Dijsktra
for v  V do { // Khởi tạo
d[v]:= a[s,v];
π[v]:= s;
}

d[s]:= 0; T:= V\{s}; // T là tập đỉnh còn có thể rút ngắn đường đi

while T !=  do { // Lặp
u := arg min (d t  t  T) ;
t
T:= T\{u} ;
for v T do
if d[v] > d[u] + a[u,v] then{
d[v]:= d[u] + a[u,v];
π[v]:= u;
}
} 24
Ví dụ
Tìm đường đi ngắn nhất từ z đến các đỉnh còn lại
u v
5
 
–2
6 –3
8
z 0 7
–4
7 2

 
9
x y

25
Ví dụ u
6
5 v

• Khởi tạo 2
6 3
8
z 0 2
1
7 2
7 
9
x y
i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z

26
Ví dụ u
6
5 v
11
• Bước lặp 1 2
6 3
8
z 0 2
1
7 2
7 7
9
x y
i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z
1 - - 11; u 7; u 7; z

27
Ví dụ u
6
5 v
11
• Bước lặp 2 2
6 3
8
z 0 5
1
7 2
7 7
9
x y
i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z
1 - - 11; u 7; u 7; z
2 - - 11; u - 7; z

28
Ví dụ u
6
5 v

• Bước lặp 3 2
6 3
8
z 0 5
1
7 2
7 
9
x y
i d[z];π[z] d[u]; π[u] d[v];π[v] d[y];π[y] d[x];π[x]
0; z 6; z ∞; z ∞; z 7; z
1 - - 11; u 7; u 7; z
2 - - 11; u - 7; z
3 - - 10; x - -

29
Ví dụ
• Tìm đường đi ngắn nhất từ đỉnh A đến các đỉnh còn lại trên đồ
thị có trọng số sau:
1
A B
3
5
3
1
1 C
F 2 1

2
1
E 4 D
Đường đi ngắn nhất trên đồ thị không có chu trình
• Định lý: Có thể đánh số các đỉnh sao cho mỗi cung của đồ thị chỉ hướng từ đỉnh
có chỉ số nhỏ hơn đến đỉnh có chỉ số lớn hơn. ((u,v) ∈ E ⟺ u < v)
• Thuật toán:
for v ∈ V do { //Khởi tạo
d[v] = a[s,v]; π[v]:= s;
}
for v ∈ V\{s} (theo thứ tự) do
for (u,v) ∈ E do
if d[v] > d[u] + a[u,v] then {
d[v] = d[u] + a[u,v];
π[v]:= s;
}
31
Ví dụ
• Tìm đường đi ngắn nhất từ đỉnh A đến các đỉnh còn lại trên đồ
thị có trọng số sau:
1
A B
3

3
1
1 C
F 2 1

2
1
E 4 D
Thuật toán Floyd
• Đường đi ngắn nhất giữa tất cả các cặp đỉnh?
• Thuật toán Floyd dựa trên ý tưởng:
• Tất cả các đường đi con của đường đi ngắn nhất là ngắn nhất
• Giả sử ma trận D = [dij](k) là đường đi ngắn nhất từ i đến j chỉ đi qua các
đỉnh trung gian 1, 2, …, k
=> Kết quả của bài toán sẽ là [dij](n)

33
Thuật toán Floyd
• Xác định dij(k):
• dij(0) = a[i, j]
• k > 0:

34
Thuật toán Floyd
• Xác định dij(k):
• dij(0) = a[i, j]
• k > 0:

dij(k) = min (dij(k-1); dik(k-1) + dkj(k-1))


35
Thuật toán Floyd
Xác định đường đi bằng ma trận đỉnh trước cuối của đường đi
• π[i, j] = Đỉnh cuối cùng trên đường đi ngắn nhất từ i đến j
• Khởi tạo: π[i, j] = i
• Tại mỗi bước lặp: xác định xem dùng đỉnh k có làm rút ngắn đường
đi từ i đến j không?
• Nếu có:
• Lưu lại trọng số của đường đi mới – ngắn hơn – từ i đến j
• Lưu lại thông tin về việc thay đổi đường đi để đi qua k

36
Thuật toán Floyd
• Lưu lại thông tin về việc thay đổi đường đi để đi qua k
=> π[i, j] = ?

37
Thuật toán Floyd
• Lưu lại thông tin về việc thay đổi đường đi để đi qua k
=> π[i, j] = π[k, j]

• Thay đổi thông tin:


If (d[i, j] > d[i, k] + d[k, j]) then {
d[i, j]:= d[i, k] + d[k, j];
π[i, j]:= π[k, j];
}

38
Thuật toán Floyd
// Khởi tạo
for i:= 1 to n do
for j:= 1 to n do {
d[i, j]:= a[i, j]; π[i, j]:= i;
}
// Bước lặp
for i:= 1 to n do
for i:= 1 to n do
for j:= 1 to n do
if (d[i, j] > d[i, k] + d[k, j]) then {
d[i, j]:= d[i, k] + d[k, j];
π[i,j]:= π[k,j];
} 39
Ví dụ
• Tìm đường đi ngắn nhất giữa tất cả các cặp đỉnh trong đồ thị:

40

You might also like