TIẾP NỐI CHƯƠNG 2 CỦA SLISE MÔN TOÁN RỜI RẠC MÌNH XIN GỬI ĐẾN CÁC BẠN CHƯƠNG 3 MÌNH MONG RẰNG VỚI NHỮNG MẪU SLIDE NÀY SẼ GIÚP MỌI NGƯỜI DỄ DÀNG HƠN KHI HỌC TẬP VÀ THỰC HÀNH MÔN NÀY ..... ,,,,,, .....
Trang 1CHƯƠNG 3: LÝ THUYẾT ĐỒ THỊ
GV: Đặng Hữu Nghị
Trang 2NỘI DUNG
3.1 •Các khái niệm cơ bản của lý thuyết đồ thị
3.2 •Biểu diễn đồ thị trên máy tính
3.3 •Các thuật toán tìm kiếm trên đồ thị
3.4 •Đồ thị Euler và đồ thị Hamilton
3.5 •Cây và cây khung của đồ thị
3.6 •Bài toán đường đi ngắn nhất
3.7 •Bài toán luồng cực đại trong mạng 2
Trang 33.6 BÀI TOÁN ĐƯỜNG ĐI NGẮN NHẤ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ó một ý nghĩa to lớn Có thể dẫn về bài
toán như vậy nhiều bài toán thực tế quan trọng
Ví dụ:
Bài toán chọn một hành trình tiết kiệm nhất
Bài toán chọn một phương pháp tiết kiệm nhất để đưa một hệ
động lực lực từ trạng thái xuất phát đến một trạng thái đích
Bài loán lựa chọn đường truyền tin với chi phí nhỏ nhất trong
mạng thông tin
V.v….
Trang 43.6.1 CÁC KHÁI NIỆM MỞ ĐẦU
Xét đồ thị G =< V, E > với |V| = n, |E| = m
Với mỗi cạnh u, v ∈ E, có một giá trị trọng số A[u, v]
Đặt A[u, v] = ∞ nếu (u, v) ∉ E
Nếu dãy v0, v1 , , vk là một đường đi trên G
thì 𝑖=1𝑘 𝐴[𝑣𝑖−1, 𝑣𝑖] được gọi là độ dài của đường đi
Bài toán: Tìm đường đi ngắn nhất từ đỉnh s đến
đỉnh t của đồ thị G
Đường đi như vậy ta sẽ gọi là đường đi ngắn nhất từ s
đến t còn độ dài của nó ta sẽ ký hiệu là d(s, t)
Nếu như không tồn tại đưòmg đi từ s đến t thì ta sẽ đặt
Trang 53.6.1 CÁC KHÁI NIỆM MỞ ĐẦU
Một tính chất của đường đi ngắn nhất nữa có thể phát
biểu một cách không hình thức như sau:
Mọi đoạn đường con của đường đi ngắn nhất cũng là đường
đi ngắn nhất.
Nếu biết khoảng cách từ s đến t, thì đường đi ngắn nhất
từ s đến t, ta có thể tìm được một cách dễ dàng.
Để tìm đường đi, chỉ cần để ý là đối với cặp đỉnh s, t ϵ
V tuỳ ý (s≠ t) luôn tìm được đỉnh v sao cho:
d(s, t) = d(s, v) + a(v, t)
đỉnh v như vậy chính là đỉnh đi trước đỉnh t trong đường
đi ngắn nhất từ s đến t.
Trang 63.6.1 CÁC KHÁI NIỆM MỞ ĐẦU
Thuật toán sau đây để tìm đường đi ngắn nhất từ s đến t
khi biết độ dài của nó
Trang 73.6.1 CÁC KHÁI NIỆM MỞ ĐẦU
procedure Find_Path;
begin
STACK := ; STACK t; v := t ;while v ≠ s do
Trang 83.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
Thuật toán được mô tả như sau:
Từ ma trận trọng số A[u,v], u, v ∈ V, tìm cận trên d[v]
của khoảng cách từ s đến tất cả các đỉnh v ∈ V
Nếu thấy d[u] + A[u,v] < d[v] thì d[v] = d[u] + A[u, v]
(làm tốt lên giá trị của d[v])
Quá trình sẽ kết thúc khi không thể làm “tốt lên” được
Trang 93.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
Khi thể hiện kỹ thuật tính toán này trên máy tính, cận
trên d[v] sẽ được gọi là nhãn của đỉnh v, còn việc tính lại
các cận trên này sẽ gọi là phép gán nhãn cho đồ thị và
toàn bộ thủ tục thường gọi là thủ tục gán nhãn
Để tính khoảng cách từ s đến t, ở đây, ta phải tính
khoảng cách từ s đến tất cả các đỉnh còn lại của đồ thị
Hiện nay vẫn chưa biết thuật toán nào cho phép tìm
đường đi ngắn nhất giữa hai đỉnh làm việc thực sự hiệu
quả hơn những thuật 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
Trang 103.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
10
Trang 113.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
Trang 123.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
12
Trang 133.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
Trang 143.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
Trang 15 Ví dụ: Xét đồ thị cho trong hình Các kết quả tính toán
theo thuật toán được mô tả trong bảng dưới đây
Trang 163.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
Bài tập: sử dụng thuật toán Ford-Bellman để tìm
đường đi ngắn nhất xuất phát từ đỉnh 1
16
Trang 173.6.2 ĐƯỜNG ĐI NGẮN NHẤT XUẤT PHÁT TỪ
MỘT ĐỈNH
Bài tập: sử dụng thuật toán Ford-Bellman để tìm
đường đi ngắn nhất xuất phát từ đỉnh 1
Trang 183.6.3 THUẬT TOÁN DIJKSTRA
Thuật toán này do E.Dijkstra, nhà toán học người Hà
Lan, đề xuất năm 1959
Thuật toán tìm đường đi ngắn nhất từ đỉnh s đến các đỉnh
còn lại được Dijkstra đề nghị áp dụng cho trường hợp đồ
thị có hướng với trọng số không âm
Thuật toán được thực hiện trên cơ sở gán tạm thời cho
các đỉnh
Nhãn của mỗi đỉnh cho biết cận trên của độ dài đường đi
ngắn nhất tới đỉnh đó
Các nhãn này sẽ được biến đổi (tính lại) nhờ một thủ tục
lặp mà ở mỗi bước lặp một số đỉnh sẽ có nhãn không
thay đổi, nhãn đó chính là độ dài đường đi ngắn nhất từ s
Trang 193.6.3 THUẬT TOÁN DIJKSTRA
Thuật toán Dijkstra
Trang 203.6.3 THUẬT TOÁN DIJKSTRA
procedure Dijkstra;
begin
for v ϵ V do begin
d[v] := a[s,v] ; Truoc[v]:=s;
end;
d[s] := 0; T := V \ {s}; (* T là tập các đỉnh có nhãn tạm thời *) while T ≠ do
begin
Tìm đỉnh u ϵ T thoả mãn d[u] = min{d[z] : z ϵ T};
T := T \ {u} ; (* Cố định nhãn của đỉnh u *) for v ϵ T do (* Gán nhãn lại cho các đỉnh trong T *)
if d[v] > d[u] + a[u, v] then begin
d[v] :=d[u] + a[u,v]; Truoc[v] := u ; end;
end;
Trang 213.6.3 THUẬT TOÁN DIJKSTRA
Ví dụ: Tim đường đi ngắn nhất từ đỉnh 1 đến các đỉnh
còn lại của đồ thị ở hình
Trang 223.6.3 THUẬT TOÁN DIJKSTRA
Kết quả tính toán theo thuật toán được trình bày trong bảng
dưới đây.
Qui ước viết hai thành phần của nhãn theo thứ tự: d[v],
Truoc[v].
Đỉnh được đánh dấu “*” là đinh được chọn để cố định nhãn ở
bước lặp dang xét, nhãn của nó không biến đổi ở các bước
Trang 243.6.3 THUẬT TOÁN DIJKSTRA
Chú ý:
Nếu chỉ cần tìm đường đi ngắn nhất từ v đến một đỉnh t
nào đó thì có thể kết thúc thuật toán khi đỉnh t trở thành
có nhãn cố định
24
Trang 253.6.3 THUẬT TOÁN DIJKSTRA
Ví dụ: Netwark → CapeMay
Trang 263.6.3 THUẬT TOÁN DIJKSTRA
26
Trang 273.6.3 THUẬT TOÁN DIJKSTRA
Trang 283.6.3 THUẬT TOÁN DIJKSTRA
28
Trang 293.6.3 THUẬT TOÁN DIJKSTRA
Trang 303.6.3 THUẬT TOÁN DIJKSTRA
30
Trang 313.6.3 THUẬT TOÁN DIJKSTRA
Trang 323.6.3 THUẬT TOÁN DIJKSTRA
32
Trang 333.6.3 THUẬT TOÁN DIJKSTRA
33
Trang 343.6.3 THUẬT TOÁN DIJKSTRA
Bài tập tìm đường từ 1 6
34
Trang 353.6.4 ĐƯỜNG ĐI NGẮN NHẤT GIỮA TẤT CẢ
Rõ ràng, khi đó ta thu được thuật toán với độ phức tạp là
O(n4) (nếu sử dụng thuật toán Ford - Bellman) hoặc
O(n3) đối với trường hợp trọng số không âm hoặc đồ thị
không có chu trình
Trong trường hợp tổng quát, sử dụng thuật toán Ford
- Bellman n lẩn không phải là cách làm tốt nhất, ở đây ta
Trang 36T HUẬT TOÁN F LOYD
Đườ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)
36
Trang 37T HUẬT TOÁN F LOYD
Xác định dij(k):
dij(0) = a[i, j]
k > 0:
Trang 38T HUẬT TOÁN F LOYD
Xác định đường đi bằng ma trân đỉnh trước cuối của đường
đi
p[i, j] = Đỉnh cuối cùng trên đường đi ngắn nhất từ i đến
j
Khởi tạo: p[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
38
Trang 39T HUẬT TOÁN F LOYD
Lưu lại thông tin về việc thay đổi đường đi để đi qua k
=> p[i, j] = p[k, j]
Thay đổi thông tin:
If (d[i, j] > d[i, k] + d[k, j]) then
Begin
d[i, j]:= d[i, k] + d[k, j];
p[i, j]:= p[k, j];
Trang 40T HUẬT TOÁN F LOYD
Thuật toán Floyd: Tim đường đi ngắn nhất giữa tất
cả các cặp đỉnh
Đầu vào:
Đồ thị cho bởi ma trận trọng số a[i, j], ị, j = 1, 2, …, n
Đầu ra :
Ma trận đường đi ngắn nhất giữa các cặp đỉnh d[i, j], i, j =
1,2,…,n trong đó d[i, j] cho độ dài đườug đi ngắn nhất từ i
đến j.
Ma trận ghi nhận đường đi p[i, j], i, j = 1, 2…, n trong đó
p[i, j] ghi nhận đỉnh đi trước đỉnh j trong đường đi
ngắn nhất từ i đến j
40
Trang 41T HUẬT TOÁN F LOYD
procedure Floyd;
begin
(* Khởi tạo *) for i :=1 to n do
for j := 1 to n do begin
d[i,j] := a[i,j];
p[i, j] := i;
end;
(* Bước lặp *) for k:= 1 to n do
Trang 42T HUẬT TOÁN F LOYD
Ta xét đồ thị vô hướng sau:
Ma trận trọng số chứa đường đi ngắn nhất ban đầu sẽ
được khởi tạo như sau:
42
Trang 43T HUẬT TOÁN F LOYD
Quá trình thực hiện thuật toán Floyd sẽ diễn ra như sau:
Chọn lần lượt từng đỉnh của đồ thị làm đỉnh trung gian (taquy ước là k)
Chọn một cặp 2 đỉnh phân biệt và không trùng với đỉnh trung gian (ta quy ước lần lượt là i và j)
Thực hiện so sánh như ở trên: đường đi ngắn nhất giữa i và j sẽ bằng giá trị nhỏ nhất của:
Giá trị đường đi ngắn nhất hiện thời giữa i và j.
Tổng của giá trị đường đi ngắn nhất hiện thời giữa i và k, và đường
đi ngắn nhất hiện thời giữa k và j.
Trang 44T HUẬT TOÁN F LOYD
Ta sẽ phân tích tuần tự theo nền tảng ý tưởng này:
Đầu tiên, k = 1 Nhờ đỉnh 1 làm trung gian, ta thấy xuất hiện
đường đi từ đỉnh 2 tới đỉnh 4 (độ dài 14), và từ đỉnh 2 tới đỉnh
5 (độ dài 6).
Đường đi trung gian qua đỉnh 1 để đi từ đỉnh 4 tới đỉnh 5
không tối ưu về chiều dài (9 + 1 > 2) nên ta không cập nhật lại
đường đi ngắn nhất giữa 2 đỉnh 4 và 5.
44
Trang 45T HUẬT TOÁN F LOYD
Tiếp theo, ta duyệt tới k = 2
Đường đi từ 3 tới 1 (độ dài 7), từ 3 tới 5 (độ dài 8) được
hình thành
Đường đi từ 3 tới 4 không cập nhật độ dài (7 < 2 + 5 +
9)
Trang 46T HUẬT TOÁN F LOYD
Cứ tiếp tục lựa chọn k như vậy cho tới hết, ta sẽ thu
được ma trận trong số hoàn chỉnh:
Giả sử, qua ma trận này, ta thấy đường đi ngắn nhất từ
đỉnh 2 tới đỉnh 4 có độ dài 8 Dựa theo đồ thị thì nó là
đoạn đường sau:
46
Trang 47T HUẬT TOÁN F LOYD
Chi tiết
Trang 48T HUẬT TOÁN F LOYD
48
Trang 49THUẬT TOÁN FLOYD
Trang 50T HUẬT TOÁN F LOYD
50
Trang 51THUẬT TOÁN FLOYD
Trang 52T HUẬT TOÁN F LOYD
Ma trận ghi nhận đường đi p[i, j], i, j = 1, 2…, n trong đó p[i, j]
ghi nhận đỉnh đi trước đỉnh j trong đường đi ngắn nhất từ i
đến j
52
Trang 53 Code Thuật toán Floyd
Trang 54int Nhap(int &n,int **&a,int **&Pi,char *fn)
Trang 55void buocthuan(int n,int **c,int **Pi)
Trang 56void inkq(int s,int f,int **pi)
Trang 57int intep(int n,int **a,int **pi)
Trang 58printf("\nNhap xuat phat s ="); scanf("%d",&s);
printf("\nNhap ket thuc f ="); scanf("%d",&f);
if(a[s][f] == -1) printf("\nKhong co duong di");
Trang 59THUẬT TOÁN FLOYD
Trang 60THUẬT TOÁN FLOYD
Trang 61BÀI TẬP
Áp dụng thuật toán Floyd để tim đường đi ngắn
nhất giữa tất cả các cặp đỉnh trong đồ thị sau: