Professional Documents
Culture Documents
11 ShortestPath
11 ShortestPath
11 ShortestPath
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
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:
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]
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