Một số thuật toán tìm đường đi ngắn nhất

Một phần của tài liệu Một số thuật toán tìm đường đi ngắn nhất và xây dựng ứng dụng GAME PIKACHU (Trang 28)

2.3.1. Bài toán tìm đường đi ngắn nhất

Để tìm kiếm đường đi từ trạng thái ban đầu tới trạng thái kết thúc trong

không gian bài toán. Giả sử rằng, tìm đường đi ngắn nhất từ trạng thái a tới trạng thái b (bởi một toán tử nào đó) là một số k(a,b)≥0, gọi số này là độ dài cung (a,b) hoặc giá trị của cung (a,b) trong đồ thị không gian trạng thái. Độ dài của các

29

Có thể giải quyết vấn đề đặt ra bằng cách tìm tất cả các đường đi có thể có từ trạng thái ban đầu tới trạng thái đích (chẳng hạn sử dụng các kỹ thuật tìm kiếm) sau đó so sánh độ dài của chúng, sẽ tìm ra đường đi ngắn nhất.

Bài toán: Cho đồ thị G = (V, E) và hai đỉnh a, b. Tìm đường đi ngắn nhất (nếu có) đi từ đỉnh a đến đỉnh b trong đồ thị G.

Thuật toán

- Lần lượt gán nhãn cho các đỉnh của đồ thị, mỗi đỉnh không quá một lần, Có thể gán nhãn như sau:

+ Đỉnh a được gán nhãn là số 0.

+ Những đỉnh kề với đỉnh a được gán nhãn là số 1.

+ Những đỉnh kề với đỉnh đã được gán nhãn số 1, được gán nhãn số 2.

+ Tổng quát ta có, những đỉnh kề với đỉnh đã được gán số i được gán nhãn là số i+1.

+ Thực hiện quá trình trên cho đến khi gán được nhãn cho đỉnh b hoặc

không gán nhãn được nữa.

- Nếu đỉnh b được gán nhãn nào đó là k thì kết luận có đường đi ngắn nhất từ đỉnh a tới đỉnh b với độ dài k, ngược lại thì trả lời là không có.

- Khôi phục đường đi: Chỉ ra b được gán nhãn k nào đó thì đi ngược lại theo quy tắc sau đây: Nếu đỉnh y được gán nhãn j với j ≥ 1 thì sẽ có đỉnh x được gãn nhãn j-1 sao cho có cạnh đi từ x tới y. Đi ngược lại cho đến khi gặp đỉnh a, khi đó sẽ nhận được đường đi ngắn nhất cần tìm.

2.3.2. Thuật toán tìm kiếm theo chiều sâu (Depth First Search - DFS) a. Tư tưởng thuật toán a. Tư tưởng thuật toán

Tìm kiếm theo chiều sâu là thuật toán duyệt hoặc tìm kiếm trên một cây hoặc một đồ thị. Thuật toán khởi đầu tại gốc (hoặc chọn một đỉnh nào đó coi như gốc) và phát triển xa nhất có thể theo mỗi nhánh. Thuật toán tìm kiếm theo chiều sâu ứng dụng cho nhiều giải thuật như: Xác định các thành phần liên thông của đồ thị, kiểm tra một đồ thị có là đồ thị phẳng hay không, …

30

Tìm kiếm sâu trong không gian bài toán được bắt đầu từ một nút rồi tiếp tục cho đến khi hoặc đến ngõ cụt hoặc đến đích. Tại mỗi nút có luật trong tài, chẳng hạn, “đi theo nút cực trái”, hướng dẫn việc tìm. Nếu không đi tiếp được, gọi là đến ngõ cụt, hệ thống quay lại một mức trên đồ thị và tìm theo hướng khác, chẳng hạn, đến nút “sát cực trái”. Như vậy được gọi là quay lui.

Thuật toán tìm kiếm theo chiều sâu được hình dung như việc khảo sát một cây bắt đầu từ gốc đi theo mọi cành có thể được, khi gặp cành cụt thì quay lại xét cành chưa đi qua.

b. Phân tích thuật toán

Tư tưởng chính của thuật toán là: Giả sử bài toán đang xét trên đồ thị

G, từ một đỉnh uhiện thời nào đó duyệt tới đỉnh kề v của u và quá trình được lặp lại đối với đỉnh v. Ở bước tổng quát, giả sử hiện tại đang xét đỉnh u0, sẽ có hai khả năng sẽ xảy ra:

- Nếu như tồn tại một đỉnh v0 kề với u0 mà chưa được thăm thì đỉnh v0 đó sẽ trở thành đỉnh đã duyệt và quá trình tìm kiếm lại bắt đầu từ đỉnh v0 đó.

- Ngược lại, nếu mọi đỉnh kề với u0 đều đã duyệt thì sẽ quay trở lại đỉnh

mà trước đó đến đỉnh u0 để tiếp tục quá trình tìm kiếm.

Như vậy, trong quá trình duyệt đỉnh bằng thuật toán tìm kiếm theo chiều sâu, đỉnh được duyệt càng muộn càng sớm được duyệt xong (Cơ chế Last In First Out - Vào sau ra trước).

c. Thuật toán

Thuật toán tìm kiếm theo chiều sâu được mô tả qua thủ tục sau:

Procedure Depth_First_Search; Begin

Khởi tạo dang sách L chỉ chứa trạng thái ban đầu u0; Loop do

If L rỗng then

31

Loại trạng thái u ở đầu dang sách L; If u là trạng thái kết thúc then

{thông báo thành công; stop}; For mỗi trạng thái v kề u do

{Đặt v vào đầu danh sách L;};

End;

Độ phức tạp thuật toán:

- Giả sử nghiệm của bài toán là đường đi có độ dài d, cây tìm kiếm có nhân tố nhánh là b và có chiều cao là d. Bài toán có thể xảy ra nghiệm là đỉnh ngoài cùng bên phải trên mức d của cây tìm kiếm, do đó độ phức tạp thời gian

của tìm kiếm theo độ sâu trong trường hợp xấu nhất là O(bd).

- Để đánh giá độ phức tạp không gian của tìm kiếm theo độ sâu, khi

phát triển một đỉnh u trên cây tìm kiếm theo độ sâu, chỉ cần lưu các đỉnh chưa

được phát triển mà chúng là các đỉnh con của các đỉnh nằm trên đường đi từ

gốc tới đỉnh u. Như vậy đối với tìm kiếm nhân tố nhánh b và độ sâu lớn nhất là d, chỉ cần lưu ít hơn bd đỉnh. Do đó độ phức tạp không gian của tìm kiếm theo độ sâu là O(bd).

d. Cách biểu diễn các trạng thái

Giải thuật tìm kiếm theo chiều sâu là giải thuật tìm kiếm theo nhánh của cây. Giải thuật bắt đầu từ nút gốc tìm kiếm đến các mức thấp hơn của nút gốc. Nếu giải thuật tìm thấy đích thì dừng thủ tục tìm kiếm và thiết lập đường lời giải từ nút gốc thông qua các nút liên tiếp đén nút đích, mặt khác nếu giải thuật tìm thấy đường cụt thì lùi về tìm kiếm các nút cùng mức.

Ví dụ: Cho không gian trạng thái của bài toán với các trạng thái được đánh nhãn bằng các chữ cái A, B, C, D, E, F, G. Hãy tìm đường đi từ A đến G bằng thuật toán tìm kiếm theo chiều sâu.

32

Hình 2.5: Sơ đồ biểu diễn trạng thái của bài toán

Thuật toán tìm kiếm theo chiều sâu bắt đầu duyệt từ đỉnh A, đi theo cạnh trái, tiếp tục tìm kiếm xong ở cây con trái mới chuyển sang tìm kiếm ở cây con phải. Thứ tự duyệt các đỉnh là: A, B, D, F, C, G, E.

Quá trình duyệt các đỉnh diễn ra như sau: Sau khi duyệt đỉnh A, vì B chưa được duyệt nên theo cạnh AB ta duyệt B, tiếp tục theo cạnh BD tới duyệt D. Từ D không thể tiếp tục đi tới đỉnh nào nữa, quay lại B. Từ B, theo BF đến duyệt F, từ F không thể tiếp tục đi được nữa nên quay lại B. Tại B, vì tất cả các khả năng từ B đã xem xét nên ta quay lại A. Từ A, theo cạnh AC tới duyệt C, tiếp tục theo cạnh CG tới duyệt G. Từ G không thể tiếp tục đi được nữa nên quay lại C. Tại C, tất cả các khả năng từ C đã xét nên lại quay về A và theo cạnh AE tới duyệt đỉnh E. Như vậy tất cả các đỉnh của đồ thị đều được duyệt đến.

2.3.3. Thuật toán tìm kiếm theo chiều rộng (Breadth First Search) a. Tư tưởng thuật toán a. Tư tưởng thuật toán

Kỹ thuật tìm kiếm rộng là tìm kiếm trên tất cả các nút của một mức trong không gian bài toán trước khi chuyển sang các nút của mức tiếp theo. Kỹ thuật tìm kiếm rộng bắt đầu từ mức thứ nhất của không gian bài toán, theo hướng dẫn của luật trọng tài, chẳng hạn “đi từ trái sang phải”. Nếu không thấy

A C D B E G F

33

lời giải tại mức này, nó chuyển xuống mức sau để tiếp tục… đến khi tìm được lời giải nếu có.

Tìm kiếm theo chiều rộng là thuật toán tìm kiếm trên tất cả các nút của một mức trong không gian bài toán trước khi di chuyển sang các nút của mức tiếp theo. Tìm kiếm theo chiều rộng chủ yếu được sử dụng để tìm đường đi ngắn nhất theo số cạnh giữa hai đỉnh của đồ thị.

b. Phân tích thuật toán

Thuật toán tìm kiếm theo chiều rộng thực ra là sự cải biến về thứ tự duyệt đỉnh trên đồ thị của tìm kiếm theo chiều sâu bằng cách thay vì dùng một ngăn xếp (STACK) thì ta lại dùng một hàng đợi (QUEUE) để kết nạp đỉnh được thăm.

Như vậy, đỉnh được duyệt càng sớm sẽ càng sớm trở thành duyệt xong (cơ chế First In First Out - Vào trước ra trước).

c. Thuật toán

Thuật toán tìm kiếm theo chiều rộng được mô tả qua thủ tục sau:

Procedure Bread_First_Search

Begin

Khởi tạo danh sách L chỉ chứa trạng thái ban đầu; Loop do

If L rỗng then

{thông báo tìm kiếm thất bại; stop}; Loại trạng thái u ở đầu danh sách L; If u là trạng thái kết thúc then

{thông báo tìm kiếm thành công, stop}; For mỗi trạng thái v kề u do {

Đặt v vào cuối danh sách L; Father(v) <-u}

34

Gọi b là nhân tố nhánh. Giả sử rằng, nghiệm của bài toán là đường đi có độ dài d. Vì nhiều nghiệm có thể được ra tại một đỉnh bất kỳ ở mức d của

cây tìm kiếm, do đó số đỉnh cần xem xét để tìm nghiệm là: 1 + b + b2 +… + bd-1 + k

Trong đó k có thể là 1, 2, …, bd. Do đó số lớn nhất các đỉnh cần xem xét là:

1 + b + b2 +… + bd

Vì cần lưu vào danh sách L tất cả các đỉnh của cây tìm kiếm ở mức d,

số các đỉnh này là bd.

Như vậy, độ phức tạp thời gian của thuật toán tìm kiếm theo chiều rộng là O(bd). Độ phức tạp không gian là O(bd)

d. Cách biểu diễn trạng thái

Giải thuật tìm kiếm theo chiều rộng là giải thuật tìm kiếm theo mức của cây. Giải thuật bắt đầu từ nút gốc của cây tìm kiếm qua tất cả các nút ở mức tiếp theo, nếu chưa tìm thấy thì vẫn tiếp tục tìm kiếm qua tất cả các nút ở mức sâu hơn, cứ như vậy cho đến khi tìm thấy nút đích thì dừng thủ tục tìm kiếm và thiết lập đường lời giải bắt đầu từ nút gốc thông qua các nút liên tiếp đến nút đích.

Ví dụ: Cho không gian trạng thái của bài toán với các trạng thái được đánh nhãn bằng các chữ cái A, B, C, D, E, F, G. Bằng thuật toán tìm kiếm theo chiều rộng tìm đường đi từ A đến G.

Theo sơ đồ biểu diễn trạng thái của bài toán (hình 2.5) thuật toán tìm kiếm theo chiều rộng bắt đầu duyệt đỉnh A, đi theo lần lượt các đỉnh con, rồi lần lượt tìm kiếm các đỉnh con phía dưới. Thứ tự duyệt các đỉnh là: A, B, C, E, D, F, G.

Quá trình duyệt các đỉnh diễn ra như sau: Sau khi duyệt đỉnh A, lần lượt duyệt hết các đỉnh con của A là B, C, E theo các cạnh tương ứng. Sau khi duyệt xong các đỉnh con của A, ta lần lượt duyệt các đỉnh con của B là D, F và lần lượt duyệt các đỉnh con của C là G. Vì E không có đỉnh con nên quay

35

về duyệt các đỉnh con của các đỉnh B, C. Các đỉnh D, F, G đều không có đỉnh con nên thuật toán kết thúc, tất cả các đỉnh của đồ thị đều đã được duyệt đến. 2.3.4. Thuật toán tìm kiếm sâu dần

a. Tư tưởng thuật toán

Tìm kiếm sâu dần là kết hợp của tìm kiếm rộng và tìm kiếm sâu trên cơ

sở cho biết mức sâu n rồi tìm kiếm rộng ứng với mức sâu đó.

Kỹ thuật tìm kiếm sâu dần là thực hiện việc tìm kiếm với mức độ sâu ở

mức giới hạn d nào đó. Nếu không tìm ra nghiệm ta tăng độ sâu lên d+1 và lại tìm kiếm theo độ sâu tới mức d+1. Quá trình trên được lặp lại với d lần lượt là

1, 2,… đến độ sâu nào dó mà bài toán yêu cầu .

Kỹ thuật tìm kiếm sâu dần thường được thực hiện khi cây tìm kiếm chứa nhánh vô hạn, và nếu sử dụng tìm kiếm theo độ sâu ta có thể mắc kẹt ở một nhánh nào đó (thuật toán không dừng) và không tìm ra nghiệm.

Vấn đề với giải thuật tìm kiếm với giới hạn độ sâu (DLS). Nếu tất cả

các lời giải (các nút đích) nằm ở độ sâu l, thì giải thuật tìm kiếm sâu dần thất

bại (không tìm được lời giải). b. Giải thuật tìm kiếm sâu dần

Áp dụng giải thuật tìm kiếm sâu dần đối với các đường đi (trong cây) có độ dài <=1.

Nếu thất bại (không tìm được lời giải) tiếp tục áp dụng giải thuật tìm kiếm sâu dần đối với các đường đi có độ dài <=2.

Nếu thất bại (không tìm được lời giải) tiếp tục áp dụng giải thuật tìm kiếm sâu dần đối với các đường đi có độ dài <=3.

Tổng quát, giải thuật tiếp tục như vậy cho đến khi: + Tìm được lời giải

36 c. Thuật toán

Thuật toán tìm kiếm sâu dần (Iterative_Depening_Search) sẽ sử dụng thuật toán tìm kiếm sâu hạn chế (Depth_ Limited_Search) như thủ tục con. Đó

là thủ tục tìm kiếm theo độ sâu, nhưng chỉ tới độ sâu d nào đó rồi quay lên. Trong thủ tục tìm kiếm sâu hạn chế, d là tham số độ sâu, hàm depth ghi

lại độ sâu của mỗi đỉnh.

Thủ tục tìm kiếm sâu hạn chế

Procedure Depth_Limited_search(d);

Begin

Khởi tạo danh sách L chỉ chứa trạng thái ban đầu u0; Depth(u0)←0;

Loop do

If L then

{thông báo thất bại; stop}; Loại trạng thái u ở đầu danh sách L; If u là trạng thái kết thúc then

{thông báo thành công; stop}; if depth(u) <= d then

for mỗi trạng thái v kề u do

{đặt v vào đầu danh sách L; Depth(v) ← depth(u) + 1}; End; Thủ tục tìm kiếm sâu dần Procedure Depth_Deepening_Search; Begin For d←0 to max do {Depth_limited_Search(d); If thành công then exit}

37 Độ phức tạp thuật toán

Mỗi lần gọi thủ tục tìm kiếm sâu hạn chế tới mức d, nếu cây tìm kiếm có nhân tố nhánh b thì số đỉnh cần phát triển là:

1 + b + b2 +… + bd

Nếu nghiệm ở độ sâu d thì trong tìm kiếm sâu dần gọi thủ tục sâu hạn chế với độ sâu lần lượt là 0, 1, 2,… , d. Do đó các đỉnh ở mức 1 phải phát triển lặp d lần, các đỉnh ở mức 2 lặp d-1 lần ,…, các đỉnh ở mức d lặp 1 lần. Như vậy tổng số đỉnh cần phát triển trong tìm kiếm sâu dần là:

(d+1)1 + db + (d-1)b2 + … + 2bd-1 + 1bd

Vậy tìm kiếm sâu dần có độ phức tạp thời gian là O(bd) (như tìm kiếm theo chiều rộng) và độ phức tạp không gian là O(bd) (như tìm kiếm theo chiều sâu) 2.3.5. Thuật toán Dijkstra tìm đường đi ngắn nhất

a. Tư tưởng thuật toán

Thuật toán Dijkstra cho phép tìm đường đi ngắn nhất từ một đỉnh s đến

các đỉnh các đỉnh còn lại của đồ thị và chiều dài (trọng số) tương ứng. Phương

pháp của thuật toán là xác định tuần tự đỉnh có chiều dài đến s theo thứ tự tăng

dần. Thuật toán được xây dựng trên cơ sở gán cho mỗi đỉnh các nhãn tạm thời. Nhãn tạm thời của các đỉnh cho biết cận trên của chiều dài đường đi ngắn nhất

từ s đến đỉnh đó. Nhãn các đỉnh sẽ biến đổi trong các bước lặp, mà ở mỗi bước

lặp sẽ có một nhãn tạm thời trở thành chính thức. Nếu nhãn của một đỉnh nào

đó trở thành chính thức thì đó cũng chính là chiều ngắn nhất của đường đi từ s

đến đỉnh đó.

b. Phân tích thuật toán

Có thể giải bài toán bằng cách xác định một tập hợp S chứa các đỉnh mà khoảng cách ngắn nhất từ đỉnh đó đến đỉnh nguồn v đã biết. Khởi đầu

S=V. Sau đó tại mỗi bước ta sẽ thêm vào S các đỉnh mà khoảng cách từ nó

đến v là ngắn nhất. Với giả thiết rằng mỗi cung có một giá trị không âm thì ta

38

đã tồn tại mảng C, tức là C[i,j] bằng giá trị (có thể xem là độ dài) của cung

(i,j). Nếu i và j không có cung nối thì ta cho C[i,j]=G. Dùng một mảng D

gồm n phần tử để lưu độ dài của đường đi ngắn nhất từ v đến mỗi đỉnh của đồ thị. Khởi đầu thì giá trị này chính là độ dài cạnh (v,i), tức D[i]=C[v,i]. Tại mỗi

Một phần của tài liệu Một số thuật toán tìm đường đi ngắn nhất và xây dựng ứng dụng GAME PIKACHU (Trang 28)