ĐƯỜNG ĐI NGẮN NHẤT TRONG ĐỒ THỊ CÓ TRỌNG SỐ 1 Các khái niệm

Một phần của tài liệu Một số vấn đề ứng dụng của đồ thị trong tin học (Trang 40 - 44)

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 a là một đường đi nào đó trong G = <X, U>

Giả sử a = xi1ui1xi2ui2 ... xin - 1uin-1xin, xijẻ X , uij ẻ U (j = 1, 2, ...,n). Khi đó ký hiệu ( )=∑n−1 ( ) gọi là trọng số của đường a

j ij u l l α x1 x 2 x3 x 4 x7 x 8 x9 x 10 x 6 x5 b a 0 1 2 3 3 3 2 1 1 2

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 a giữa a và b là ngắn nhất nếu a thoả mãn l(a) = min {l(b) / bẻ 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(a) thì

s(x) = l(a) 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à s(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ố s(x). Nếu tồn tại đỉnh y có trọng số s(y) từ y sang x mà s(x) > s(y) + l(y, x) thì ta thay trọng số của s(x) bởi trọng số s'(x) = s(y) + l(y, x). Trường hợp s(x) < s(y) + l(y, x), trọng số của x giữ nguyên là s(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à s(y) + l(y, x) < s(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 xin có tính chất s(b) = s(x) + l(xin, b). Nếu không có đỉnh kề với xin 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 xin ta đi ngược về đỉnh xin-1 có tính chất s(xin) = s(in-1) + l(xin-1, xin) nếu không đi về đỉnh kề với xin mà trọng số cạnh (cung) giữa chúng là ít nhất.

Bằng cách đó ta sẽ đi về đỉnh xi1 mà đỉnh kề là a sao cho s(xi1) = s(a) + l(a, xi1) = l(a, xi1) với s(a) = 0.

Đường a = axi1xi2 ... xin - 1xinb 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(a) = l(a,xi1) + l(xi1,xi2) + ... + l(xin-1,xin) + l(xin,b) = [s(xi1)- s(a)] + [s(xi2) - s(xi1)] + ...

+ [s(xin) - s(xin-1)] + [s(b) - s(xin)] = s(b) (1)

Giả sử bẻ D(a, b) là 1 đường bất kỳ từ a đến b và có dạng:

l(a, xj1) ³ s(xj1) - s(a) = s(xj1) l(xj1, xj2) ³ s(xj2) - s(xj1) ... l(xjk-1,xjk) ³ s(xjk) - s(xjk-1) l(xjk, b) ³ s(b) - s(xjk) Cộng 2 vế ta có: l(b) = l(a, xj1) + l(xj1, xj2) + ... + l(xjn-1, xjk) + l(xjk, b) ³ s(b) (2) So sánh (1) và (2) ta có: l(a) = min{ l(b) / bẻ 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 = v0, v1, ..., vn = b và trọng số l(vi, vj) = Ơ nếu (vi, vj) ẽ U của G}

For i:=1 to n s(vi) := Ơ;

s(a) := 0; S := f

{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ó s(u) nhỏ nhất; S := S ẩ {u};

For tất cả các đỉnh v không thuộc S

if s(u) + l(u,v) < s(v) then s(v) := s(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(a) = 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(n2), tức là phải dùng O(n2) 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

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 s(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 s(x) := t[a, x]; Truoc[x] := a; End; s(a) := 0; For k:=1 to n - 2 do For x ẻ X \ {a} do For y ẻ X do

if s(x) > s(y) + t[y, x] then begin s(x) := s(y) + t[y, x];

Truoc(x) := y; End;

End;

Độ phức tạp của thuật toán là O(n3) 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 s(x) > s(y) + t[y, x] then begin

s(x) := s(y) + t[y, x]; Truoc(x) := y;

End;

2.4 Thuật toán Floyd.

Trong nhiều trường hợp ta cần xác định đường đi ngắn nhất giữa tất cả các cặp đỉnh, với bài toán này có thể giải bằng cách sử dụng n lần thuật toán thuật toán Ford_bellman trong đó ta sẽ chọn s lần lượt là các đỉnh của đồ thị cách làm này không phải là cách làm tốt nhất ở đây, ta sẽ trình bày thuật toán để giải quyết bài toán này trên đó là thuật toán Floyd. Thuật toán được trình bày khái quát ở dạng thủ tục sau:

Procedure Floyd;

{ Input: đồ thị cho bởi ma trận trọng số a[i,j], i,j = 1,2,...,n; Output: Ma trận đường đi ngắn nhất giữa tất cả các cặp đỉnh. d[i,j], i,j = 1,2,...n. Trong đó d[i,j] cho độ dài ngắn nhất từ i đến j Ma trận ghi nhận đường đi p[i,j] ghi nhận đường đi trước đỉnh j} Begin For i:=1 to n do For j:=1 to n do Begin d[i,j] := a[i,j] p[i,j] := i; End; For k:=1 to n do For i:=1 to n do For j:=1 to n do

if d[i,j] > d[j,k] + d[k,j] then Begin d[i, j] := d[i, k] + d[k,j];

p[i,j] := p[k,j]; End;

End;

Một phần của tài liệu Một số vấn đề ứng dụng của đồ thị trong tin học (Trang 40 - 44)

Tải bản đầy đủ (DOC)

(81 trang)
w