CHƯƠNG 5
ĐƯỜNG ĐI NGẮN NHẤT TRÊN ĐỒ THỊ
Tôn Quang Toại Khoa CNTT, Đại học Ngoại ngữ ‐ Tin học TP.HCM
Nội dung
Các khái niệm mở đầu Phát biểu bài toán Thuật toán Dijkstra Thuật toán Ford – Bellman Thuật toán Floyd
Các khái niệm mở đầu
Đồ thị có trọng số: Đồ thị G=(V, E) có trọng số khi mỗi cạnh e=(u,v) của đồ thị được gán với một con số w(u,v) và được gọi là trọng số của cạnh e.
(cid:2870)
(cid:2869)
Đường đi: Đường đi giữa 2 đỉnh s và t được cho bởi là dãy đỉnh (cid:3040) trong đó:
(cid:2869)
(cid:3040)
(cid:3036)
(cid:3036)(cid:2878)(cid:2869)
Các khái niệm mở đầu
Độ dài đường đi: Độ dài đường đi là tổng trọng số của tất cả các cạnh trên đường đi đó
(cid:3040)(cid:2879)(cid:2869)
(cid:3036)(cid:2880)(cid:2869)
𝑤 𝑝 (cid:3404) (cid:3533) 𝑤(cid:4666)𝑥(cid:3036), 𝑥(cid:3036)(cid:2878)(cid:2869)(cid:4667)
Phát biểu bài toán
Ví dụ:
18
b
c
12
p = (a, d, f, g) w(p) = 6 + 8 + 2 = 16
4
3
2
7
g
6
a
d
8
2
3
9
4
f
e
14
Các khái niệm mở đầu
Biểu diễn đồ thị trọng số Cách 1: Ma trận trọng số
𝑣(cid:3036)(cid:3037) (cid:3404) (cid:4682) 0/∞ 𝑛ế𝑢 (cid:4666)𝑖, 𝑗(cid:4667) ∉ 𝐸 𝑤(cid:4666)𝑖, 𝑗(cid:4667) 𝑛ế𝑢(cid:4666)𝑖, 𝑗(cid:4667) ∈ 𝐸
int[,] v; int n;
Các khái niệm mở đầu
Cách 2: Danh sách cạnh
LinkedList> e;
Cách 3: Danh sách kề
LinkedList>[] v;
Phát biểu bài toán
Phát biểu bài toán:
Cho đồ thị G=(V, E) có trọng số và hai đỉnh s và t cho trước. Hãy tìm 1 đường đi từ s đến t sao cho độ dài đường đi là ngắn nhất
Phát biểu bài toán
18
c
b
12
Ví dụ:
4
3
2
7
p = (a, d, f, g) w(p) = 6 + 8 + 2 = 16
g = t
6
s = a
d
8
2
3
9
4
f
e
pshortest = (s, ,t) w(pshortest) =
14
Thuật toán Dijkstra
Giả định của thuật toán Dijkstra Không có cạnh âm trong đồ thị s và t liên thông với nhau
Ý tưởng thuật toán Dijkstra:
Mỗi đỉnh của đồ thị, ta gán một giá trị dist[i]: là độ dài đường đi ngắn nhất từ s đến i. Nhiệm vụ: Giảm giá trị mảng dist[ ] từng bước.
Thuật toán Dijkstra
Thuật toán Dijkstra:
Input: G=(V, E) và 2 đỉnh s, t Output: 𝑑𝑖𝑠𝑡(cid:4670)(cid:4671)
Bước 1 (Khởi tạo)
• 𝑑𝑖𝑠𝑡 𝑖 (cid:3404) (cid:3397)∞, ∀𝑖 ∈ 𝑉 • 𝑑𝑖𝑠𝑡 𝑠 (cid:3404) 0 • Tập S=V (S là tập đỉnh chưa xét)
Bước 2 (Lặp)
• Tìm min: Chọn đỉnh 𝑎 ∈ 𝑆 sao cho 𝑑𝑖𝑠𝑡 𝑎 có giá trị nhỏ nhất
• Cập Nhật: Với mọi đỉnh b kề đỉnh a
– Nếu dist[b]>dist[a] + w(a,b) thì dist[b]=dist[a] + w(a,b) và pre[b]=a
• S = S ‐ {a} (đỉnh a đã xét xong, bỏ khỏi tập S)
Lặp cho đến khi t S (đỉnh t được xét)
Thuật toán Dijkstra
Giải thích bước cập nhật:
Khi gán 𝑑𝑖𝑠𝑡 𝑏 (cid:3404) 𝑑𝑖𝑠𝑡 𝑎 (cid:3397) 𝑤 𝑎, 𝑏 tức là ta đã phát hiện ra 1 đường đi mới đến b có độ dài ngắn hơn
𝑑𝑖𝑠𝑡(cid:4666)𝑏(cid:4667) 𝑏
𝑑𝑖𝑠𝑡 𝑏 (cid:3408) 𝑑𝑖𝑠𝑡 𝑎 (cid:3397) 𝑤(cid:4666)𝑎, 𝑏(cid:4667)
Đường đi cũ
Đường đi mới
𝑤(cid:4666)𝑎, 𝑏(cid:4667)
𝑠
𝒂 𝑑𝑖𝑠𝑡(cid:4666)𝑎(cid:4667)
Và đường đi đó trước khi tới b phải qua a vì vậy để tìm liệt kê các đỉnh đường đi chúng ta dùng 1 mảng pre[]. Trong đó pre[b]=a cho biết đỉnh ngay trước đỉnh b là đỉnh a.
Ví dụ
Ví dụ 1: Dùng thuật toán Dijkstra Tìm đường đi ngắn nhất từ a đến g
18
c
b
12
4
3
2
7
g=t
6
d
s=a
8
2
3
9
4
f
e
14
Ví dụ
Lưu ý:
Thuật toán Dijkstra có thể áp dùng tìm đường đi ngắn nhất từ một đỉnh đến tất các các đỉnh còn lại (chúng ta chỉ cần sửa lại điều kiện kết thúc vòng lặp là S=Ø)
Ví dụ
Ví dụ 2: Tìm đường đi ngắn nhất từ đỉnh c đến các đỉnh còn lại theo thuật toán Dijkstra
b d f 5 5
4 3
3 2 2 h a 1 1
3 1
6 c 3 g e
Cài đặt
Cấu trúc dữ liệu:
dist[i]: Lưu độ dài đường đi ngắn nhất từ s đến i
pre[i]: Lưu đỉnh trước của đỉnh i
label[i]:
true: 𝒊 ∉ 𝑺 false: 𝒊 ∈ 𝑺
path[]: lưu các đỉnh của đường đi
Cài đặt
Input
LinkedList
Output
int[] dist;
bool[] label;
int[] pre;
LinkedList
Cài đặt
void Dijkstra(int s) {
// B1: Khởi tạo
for (int i=0; i
for (int i=0; i
// B2: Lặp: Tìm min + cập nhật
for (int k=0; k
Cài đặt
void TruyVet(int s, int t)
{
path = new LinkedList();
for (i=t; i!=-1; i=pre[i])
path.AddFirst(i);
}
Thuật toán Bellman – Ford
Thuật toán Dijkstra không thể thực hiện khi đồ
thị có cạnh âm (đồ thị vô hướng) hay đồ thị có
chu trình âm có thể đến được (đồ thị có
hướng)
Thuật toán Bellman – Ford xác định các chu
trình âm hay trả về cây đường đi ngắn nhất
Thuật toán Bellman – Ford
Thuật toán Bellman – Ford
• 𝑑(cid:2868) 𝑖 (cid:3404) (cid:3397)∞, ∀𝑖 ∈ 𝑉
• 𝑑(cid:2868) 𝑠 (cid:3404) 0
• k=0
Bước 1 (Khởi tạo)
– 𝑑(cid:3038) 𝑠 (cid:3404) 0
– 𝑑(cid:3038) 𝑏 (cid:3404) min 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑎 (cid:3397) 𝑤 𝑎, 𝑏
• Kiểm tra:
– Nếu 𝑑(cid:3038) 𝑖 (cid:3404) 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑖 , ∀𝑖 ∈ 𝑉 (tức là 𝑑(cid:3038) 𝑖 đã ổn định) thì dừng thuật toán
Bước 2 (Lặp)
• k = k+1
• Cập Nhật: Với mọi đỉnh a kề̀ b
Lặp cho đến khi k=n
Bước 3: Nếu k=n thì đồ thị có chu trình âm
Ví dụ
Ví dụ 1: Dùng thuật toán Bellman – Ford Tìm
đường đi ngắn nhất từ a đến các đỉnh còn lại
18
b
c
12
4
3
2
7
g
6
s=a
d
8
2
3
9
4
f
e
14
Ví dụ
Ví dụ 2: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
2 4 6 5 5
4 3
3 2 2 8 1 1 1
3 1
6 3 3 7 5
Ví dụ
Ví dụ 3: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
b e 5
2 4 7
a 3 6 f
-6
3
6
6 c d
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall: Thuật toán Floyd
– Warshall cho chúng ta cách tìm đường đi
ngắn nhất giữa tất cả các cặp đỉnh hoặc chỉ ra
đồ thị có chu trình âm
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Input: G=(V, E)
Output:
• Ma trận đường đi ngắn nhất giữa các cặp đỉnh
– d[i, j]: độ dài đường đi ngắn nhất từ đỉnh i đến đỉnh j
– pre[i, j]: ghi nhận đỉnh đi trước đỉnh j trong đường đi ngắn nhất
từ đỉnh i đến đỉnh j
• Ma trận ghi nhận đường đi
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Bước 1 (Khởi tạo)
• 𝑑 𝑖, 𝑗 (cid:3404) (cid:4682) 𝑎(cid:4670)𝑖, 𝑗(cid:4671), (cid:4666)𝑖, 𝑗(cid:4667) ∈ 𝑉
(cid:3397)∞, (cid:4666)𝑖, 𝑗(cid:4667) ∉ 𝑉
for (int k=0; kd[i,k]+d[k,j]) {
d[i,j] = d[i,k]+d[k,j];
pre[i,j] = pre[k,j];
}
• pre 𝑖, 𝑗 (cid:3404) 𝑖
Bước 2 (Lặp)
Bài tập
Bài tập 1: Tìm đường đi ngắn nhất từ u đến các
đỉnh còn lại bằng thuật toán Dijkstra
s 7 r
1 3 4 3 x
u 1 2 3 t
1 4
w z y 3 5
Bài tập
Bài tập 2: Cho đồ thị có trọng số G = (V, E), V = {
v1, v2, v3, v4, v5, v6 , v7} xác định bởi ma trận
trọng số D. Dùng thuật toán Dijkstra tìm đường
đi ngắn nhất từ v1 đến các đỉnh v2, v3, v4, v5,
v6, v7
Bài tập
0
5
31
40
27
0
0
26
73
49
D
8
0
25
38
16
70
0
0
23
10
9
12
0
Bài tập
Bài tập 3: Cho một ví dụ chứng tỏ rằng thuật
toán Dijkstra để tìm đường đi ngắn nhất từ
một đỉnh đến các đỉnh khác không áp dụng
được cho đồ thị có trọng số nếu có cạnh có
trọng số âm
Bài tập
Bài tập 4: Dùng thuật toán Dijsktra để tìm
đường đi ngắn nhất từ đỉnh a đến các đỉnh còn
lại trong đồ thị vô hướng có trọng số sau:
b f d 5 5
7 4
3 2 z 2 1 a
4 3
g c e 6 5
Chọn lựa thuật toán
Thuật toán
Lý do chọn
Tùy ngữ cảnh của bài toán chúng ta phải chọn
lựa thuật toán tìm đường đi ngắn nhất cho phù
hợp
STT
1
Dijkstra
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị chỉ có cạnh trọng số dương
• Số đỉnh lớn: 𝑛, 𝑚 (cid:3409) 10(cid:2874)
• Độ phức tạp: 𝑂(cid:4666)𝑚. log (cid:4666)𝑛(cid:4667)(cid:4667)
2
Bellman – Ford
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị có thể có chu trình âm
• Độ phức tạp: 𝑂(cid:4666)𝑚. 𝑛(cid:4667)
3
Floyd – Warshall
• Tìm đường đi ngắn nhất giữa tất cả cập đỉnh
• Số đỉnh nhỏ: 𝑛 (cid:3409) 500
• Độ phức tạp: 𝑂 𝑛(cid:2871)
Tóm tắt chương 5
Thuật toán Dijkstra
Thuật toán Bellman – Ford
Thuật toán Floyd – Warshall
for (int i=0; i
// B2: Lặp: Tìm min + cập nhật
for (int k=0; k
Cài đặt
void TruyVet(int s, int t)
{
path = new LinkedList();
for (i=t; i!=-1; i=pre[i])
path.AddFirst(i);
}
Thuật toán Bellman – Ford
Thuật toán Dijkstra không thể thực hiện khi đồ
thị có cạnh âm (đồ thị vô hướng) hay đồ thị có
chu trình âm có thể đến được (đồ thị có
hướng)
Thuật toán Bellman – Ford xác định các chu
trình âm hay trả về cây đường đi ngắn nhất
Thuật toán Bellman – Ford
Thuật toán Bellman – Ford
• 𝑑(cid:2868) 𝑖 (cid:3404) (cid:3397)∞, ∀𝑖 ∈ 𝑉
• 𝑑(cid:2868) 𝑠 (cid:3404) 0
• k=0
Bước 1 (Khởi tạo)
– 𝑑(cid:3038) 𝑠 (cid:3404) 0
– 𝑑(cid:3038) 𝑏 (cid:3404) min 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑎 (cid:3397) 𝑤 𝑎, 𝑏
• Kiểm tra:
– Nếu 𝑑(cid:3038) 𝑖 (cid:3404) 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑖 , ∀𝑖 ∈ 𝑉 (tức là 𝑑(cid:3038) 𝑖 đã ổn định) thì dừng thuật toán
Bước 2 (Lặp)
• k = k+1
• Cập Nhật: Với mọi đỉnh a kề̀ b
Lặp cho đến khi k=n
Bước 3: Nếu k=n thì đồ thị có chu trình âm
Ví dụ
Ví dụ 1: Dùng thuật toán Bellman – Ford Tìm
đường đi ngắn nhất từ a đến các đỉnh còn lại
18
b
c
12
4
3
2
7
g
6
s=a
d
8
2
3
9
4
f
e
14
Ví dụ
Ví dụ 2: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
2 4 6 5 5
4 3
3 2 2 8 1 1 1
3 1
6 3 3 7 5
Ví dụ
Ví dụ 3: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
b e 5
2 4 7
a 3 6 f
-6
3
6
6 c d
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall: Thuật toán Floyd
– Warshall cho chúng ta cách tìm đường đi
ngắn nhất giữa tất cả các cặp đỉnh hoặc chỉ ra
đồ thị có chu trình âm
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Input: G=(V, E)
Output:
• Ma trận đường đi ngắn nhất giữa các cặp đỉnh
– d[i, j]: độ dài đường đi ngắn nhất từ đỉnh i đến đỉnh j
– pre[i, j]: ghi nhận đỉnh đi trước đỉnh j trong đường đi ngắn nhất
từ đỉnh i đến đỉnh j
• Ma trận ghi nhận đường đi
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Bước 1 (Khởi tạo)
• 𝑑 𝑖, 𝑗 (cid:3404) (cid:4682) 𝑎(cid:4670)𝑖, 𝑗(cid:4671), (cid:4666)𝑖, 𝑗(cid:4667) ∈ 𝑉
(cid:3397)∞, (cid:4666)𝑖, 𝑗(cid:4667) ∉ 𝑉
for (int k=0; kd[i,k]+d[k,j]) {
d[i,j] = d[i,k]+d[k,j];
pre[i,j] = pre[k,j];
}
• pre 𝑖, 𝑗 (cid:3404) 𝑖
Bước 2 (Lặp)
Bài tập
Bài tập 1: Tìm đường đi ngắn nhất từ u đến các
đỉnh còn lại bằng thuật toán Dijkstra
s 7 r
1 3 4 3 x
u 1 2 3 t
1 4
w z y 3 5
Bài tập
Bài tập 2: Cho đồ thị có trọng số G = (V, E), V = {
v1, v2, v3, v4, v5, v6 , v7} xác định bởi ma trận
trọng số D. Dùng thuật toán Dijkstra tìm đường
đi ngắn nhất từ v1 đến các đỉnh v2, v3, v4, v5,
v6, v7
Bài tập
0
5
31
40
27
0
0
26
73
49
D
8
0
25
38
16
70
0
0
23
10
9
12
0
Bài tập
Bài tập 3: Cho một ví dụ chứng tỏ rằng thuật
toán Dijkstra để tìm đường đi ngắn nhất từ
một đỉnh đến các đỉnh khác không áp dụng
được cho đồ thị có trọng số nếu có cạnh có
trọng số âm
Bài tập
Bài tập 4: Dùng thuật toán Dijsktra để tìm
đường đi ngắn nhất từ đỉnh a đến các đỉnh còn
lại trong đồ thị vô hướng có trọng số sau:
b f d 5 5
7 4
3 2 z 2 1 a
4 3
g c e 6 5
Chọn lựa thuật toán
Thuật toán
Lý do chọn
Tùy ngữ cảnh của bài toán chúng ta phải chọn
lựa thuật toán tìm đường đi ngắn nhất cho phù
hợp
STT
1
Dijkstra
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị chỉ có cạnh trọng số dương
• Số đỉnh lớn: 𝑛, 𝑚 (cid:3409) 10(cid:2874)
• Độ phức tạp: 𝑂(cid:4666)𝑚. log (cid:4666)𝑛(cid:4667)(cid:4667)
2
Bellman – Ford
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị có thể có chu trình âm
• Độ phức tạp: 𝑂(cid:4666)𝑚. 𝑛(cid:4667)
3
Floyd – Warshall
• Tìm đường đi ngắn nhất giữa tất cả cập đỉnh
• Số đỉnh nhỏ: 𝑛 (cid:3409) 500
• Độ phức tạp: 𝑂 𝑛(cid:2871)
Tóm tắt chương 5
Thuật toán Dijkstra
Thuật toán Bellman – Ford
Thuật toán Floyd – Warshall
// B2: Lặp: Tìm min + cập nhật
for (int k=0; k
Cài đặt
void TruyVet(int s, int t)
{
path = new LinkedList();
for (i=t; i!=-1; i=pre[i])
path.AddFirst(i);
}
Thuật toán Bellman – Ford
Thuật toán Dijkstra không thể thực hiện khi đồ
thị có cạnh âm (đồ thị vô hướng) hay đồ thị có
chu trình âm có thể đến được (đồ thị có
hướng)
Thuật toán Bellman – Ford xác định các chu
trình âm hay trả về cây đường đi ngắn nhất
Thuật toán Bellman – Ford
Thuật toán Bellman – Ford
• 𝑑(cid:2868) 𝑖 (cid:3404) (cid:3397)∞, ∀𝑖 ∈ 𝑉
• 𝑑(cid:2868) 𝑠 (cid:3404) 0
• k=0
Bước 1 (Khởi tạo)
– 𝑑(cid:3038) 𝑠 (cid:3404) 0
– 𝑑(cid:3038) 𝑏 (cid:3404) min 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑎 (cid:3397) 𝑤 𝑎, 𝑏
• Kiểm tra:
– Nếu 𝑑(cid:3038) 𝑖 (cid:3404) 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑖 , ∀𝑖 ∈ 𝑉 (tức là 𝑑(cid:3038) 𝑖 đã ổn định) thì dừng thuật toán
Bước 2 (Lặp)
• k = k+1
• Cập Nhật: Với mọi đỉnh a kề̀ b
Lặp cho đến khi k=n
Bước 3: Nếu k=n thì đồ thị có chu trình âm
Ví dụ
Ví dụ 1: Dùng thuật toán Bellman – Ford Tìm
đường đi ngắn nhất từ a đến các đỉnh còn lại
18
b
c
12
4
3
2
7
g
6
s=a
d
8
2
3
9
4
f
e
14
Ví dụ
Ví dụ 2: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
2 4 6 5 5
4 3
3 2 2 8 1 1 1
3 1
6 3 3 7 5
Ví dụ
Ví dụ 3: Tìm đường đi ngắn nhất từ đỉnh a đến
các đỉnh còn lại bằng thuật toán Bellman – Ford
b e 5
2 4 7
a 3 6 f
-6
3
6
6 c d
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall: Thuật toán Floyd
– Warshall cho chúng ta cách tìm đường đi
ngắn nhất giữa tất cả các cặp đỉnh hoặc chỉ ra
đồ thị có chu trình âm
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Input: G=(V, E)
Output:
• Ma trận đường đi ngắn nhất giữa các cặp đỉnh
– d[i, j]: độ dài đường đi ngắn nhất từ đỉnh i đến đỉnh j
– pre[i, j]: ghi nhận đỉnh đi trước đỉnh j trong đường đi ngắn nhất
từ đỉnh i đến đỉnh j
• Ma trận ghi nhận đường đi
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Bước 1 (Khởi tạo)
• 𝑑 𝑖, 𝑗 (cid:3404) (cid:4682) 𝑎(cid:4670)𝑖, 𝑗(cid:4671), (cid:4666)𝑖, 𝑗(cid:4667) ∈ 𝑉
(cid:3397)∞, (cid:4666)𝑖, 𝑗(cid:4667) ∉ 𝑉
for (int k=0; kd[i,k]+d[k,j]) {
d[i,j] = d[i,k]+d[k,j];
pre[i,j] = pre[k,j];
}
• pre 𝑖, 𝑗 (cid:3404) 𝑖
Bước 2 (Lặp)
Bài tập
Bài tập 1: Tìm đường đi ngắn nhất từ u đến các
đỉnh còn lại bằng thuật toán Dijkstra
s 7 r
1 3 4 3 x
u 1 2 3 t
1 4
w z y 3 5
Bài tập
Bài tập 2: Cho đồ thị có trọng số G = (V, E), V = {
v1, v2, v3, v4, v5, v6 , v7} xác định bởi ma trận
trọng số D. Dùng thuật toán Dijkstra tìm đường
đi ngắn nhất từ v1 đến các đỉnh v2, v3, v4, v5,
v6, v7
Bài tập
0
5
31
40
27
0
0
26
73
49
D
8
0
25
38
16
70
0
0
23
10
9
12
0
Bài tập
Bài tập 3: Cho một ví dụ chứng tỏ rằng thuật
toán Dijkstra để tìm đường đi ngắn nhất từ
một đỉnh đến các đỉnh khác không áp dụng
được cho đồ thị có trọng số nếu có cạnh có
trọng số âm
Bài tập
Bài tập 4: Dùng thuật toán Dijsktra để tìm
đường đi ngắn nhất từ đỉnh a đến các đỉnh còn
lại trong đồ thị vô hướng có trọng số sau:
b f d 5 5
7 4
3 2 z 2 1 a
4 3
g c e 6 5
Chọn lựa thuật toán
Thuật toán
Lý do chọn
Tùy ngữ cảnh của bài toán chúng ta phải chọn
lựa thuật toán tìm đường đi ngắn nhất cho phù
hợp
STT
1
Dijkstra
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị chỉ có cạnh trọng số dương
• Số đỉnh lớn: 𝑛, 𝑚 (cid:3409) 10(cid:2874)
• Độ phức tạp: 𝑂(cid:4666)𝑚. log (cid:4666)𝑛(cid:4667)(cid:4667)
2
Bellman – Ford
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại
• Đồ thị có thể có chu trình âm
• Độ phức tạp: 𝑂(cid:4666)𝑚. 𝑛(cid:4667)
3
Floyd – Warshall
• Tìm đường đi ngắn nhất giữa tất cả cập đỉnh
• Số đỉnh nhỏ: 𝑛 (cid:3409) 500
• Độ phức tạp: 𝑂 𝑛(cid:2871)
Tóm tắt chương 5
Thuật toán Dijkstra
Thuật toán Bellman – Ford
Thuật toán Floyd – Warshall
Cài đặt
void TruyVet(int s, int t)
{
path = new LinkedList();
for (i=t; i!=-1; i=pre[i]) path.AddFirst(i); }
Thuật toán Bellman – Ford
Thuật toán Dijkstra không thể thực hiện khi đồ thị có cạnh âm (đồ thị vô hướng) hay đồ thị có chu trình âm có thể đến được (đồ thị có hướng)
Thuật toán Bellman – Ford xác định các chu trình âm hay trả về cây đường đi ngắn nhất
Thuật toán Bellman – Ford
Thuật toán Bellman – Ford
• 𝑑(cid:2868) 𝑖 (cid:3404) (cid:3397)∞, ∀𝑖 ∈ 𝑉 • 𝑑(cid:2868) 𝑠 (cid:3404) 0 • k=0
Bước 1 (Khởi tạo)
– 𝑑(cid:3038) 𝑠 (cid:3404) 0 – 𝑑(cid:3038) 𝑏 (cid:3404) min 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑎 (cid:3397) 𝑤 𝑎, 𝑏
• Kiểm tra:
– Nếu 𝑑(cid:3038) 𝑖 (cid:3404) 𝑑(cid:3038)(cid:2879)(cid:2869) 𝑖 , ∀𝑖 ∈ 𝑉 (tức là 𝑑(cid:3038) 𝑖 đã ổn định) thì dừng thuật toán
Bước 2 (Lặp) • k = k+1 • Cập Nhật: Với mọi đỉnh a kề̀ b
Lặp cho đến khi k=n
Bước 3: Nếu k=n thì đồ thị có chu trình âm
Ví dụ
Ví dụ 1: Dùng thuật toán Bellman – Ford Tìm đường đi ngắn nhất từ a đến các đỉnh còn lại
18
b
c
12
4
3
2
7
g
6
s=a
d
8
2
3
9
4
f
e
14
Ví dụ
Ví dụ 2: Tìm đường đi ngắn nhất từ đỉnh a đến các đỉnh còn lại bằng thuật toán Bellman – Ford
2 4 6 5 5
4 3
3 2 2 8 1 1 1
3 1
6 3 3 7 5
Ví dụ
Ví dụ 3: Tìm đường đi ngắn nhất từ đỉnh a đến các đỉnh còn lại bằng thuật toán Bellman – Ford
b e 5
2 4 7
a 3 6 f
-6
3
6
6 c d
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall: Thuật toán Floyd – Warshall cho chúng ta cách tìm đường đi ngắn nhất giữa tất cả các cặp đỉnh hoặc chỉ ra đồ thị có chu trình âm
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Input: G=(V, E) Output: • Ma trận đường đi ngắn nhất giữa các cặp đỉnh – d[i, j]: độ dài đường đi ngắn nhất từ đỉnh i đến đỉnh j
– pre[i, j]: ghi nhận đỉnh đi trước đỉnh j trong đường đi ngắn nhất
từ đỉnh i đến đỉnh j
• Ma trận ghi nhận đường đi
Thuật toán Floyd – Warshall
Thuật toán Floyd – Warshall:
Bước 1 (Khởi tạo)
• 𝑑 𝑖, 𝑗 (cid:3404) (cid:4682) 𝑎(cid:4670)𝑖, 𝑗(cid:4671), (cid:4666)𝑖, 𝑗(cid:4667) ∈ 𝑉 (cid:3397)∞, (cid:4666)𝑖, 𝑗(cid:4667) ∉ 𝑉
for (int k=0; k
• pre 𝑖, 𝑗 (cid:3404) 𝑖 Bước 2 (Lặp)
Bài tập
Bài tập 1: Tìm đường đi ngắn nhất từ u đến các đỉnh còn lại bằng thuật toán Dijkstra
s 7 r
1 3 4 3 x
u 1 2 3 t
1 4
w z y 3 5
Bài tập
Bài tập 2: Cho đồ thị có trọng số G = (V, E), V = { v1, v2, v3, v4, v5, v6 , v7} xác định bởi ma trận trọng số D. Dùng thuật toán Dijkstra tìm đường đi ngắn nhất từ v1 đến các đỉnh v2, v3, v4, v5, v6, v7
Bài tập
0
5
31
40
27 0
0 26
73 49
D
8 0
25 38 16
70
0
0 23 10
9 12 0
Bài tập
Bài tập 3: Cho một ví dụ chứng tỏ rằng thuật toán Dijkstra để tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh khác không áp dụng được cho đồ thị có trọng số nếu có cạnh có trọng số âm
Bài tập
Bài tập 4: Dùng thuật toán Dijsktra để tìm đường đi ngắn nhất từ đỉnh a đến các đỉnh còn lại trong đồ thị vô hướng có trọng số sau:
b f d 5 5
7 4
3 2 z 2 1 a
4 3
g c e 6 5
Chọn lựa thuật toán
Thuật toán
Lý do chọn
Tùy ngữ cảnh của bài toán chúng ta phải chọn lựa thuật toán tìm đường đi ngắn nhất cho phù hợp STT 1
Dijkstra
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại • Đồ thị chỉ có cạnh trọng số dương • Số đỉnh lớn: 𝑛, 𝑚 (cid:3409) 10(cid:2874) • Độ phức tạp: 𝑂(cid:4666)𝑚. log (cid:4666)𝑛(cid:4667)(cid:4667)
2
Bellman – Ford
• Tìm đường đi ngắn nhất từ một đỉnh đến các đỉnh còn lại • Đồ thị có thể có chu trình âm • Độ phức tạp: 𝑂(cid:4666)𝑚. 𝑛(cid:4667)
3
Floyd – Warshall
• Tìm đường đi ngắn nhất giữa tất cả cập đỉnh • Số đỉnh nhỏ: 𝑛 (cid:3409) 500 • Độ phức tạp: 𝑂 𝑛(cid:2871)