Nghiên cứu một số thuật toán trong GIS có ứng dụng logic mờ

Một phần của tài liệu nghiên cứu một số thuật toán trong gis ứng dụng logic mờ (Trang 46)

2.2.1. Một số thuật toán tìm đƣờng đi tối ƣu ứng dụng trong GIS

2.2.1.1. Phát biểu bài toán

Các thuật toán đồ thị nổi tiếng xác định đường đi “ngắn nhất ” giữa hai điểm A và B trên mạng lưới đường phố mà tiêu chuẩn “ngắn nhất” có thể được dựa trên khoảng cách, thời gian đi hoặc một số ràng buộc khác do người sử dụng tự đặt ra.

Giả sử cho đồ thị G trong đó có khung (x, y) gắn với trọng số của khung a(x, y). Trong một số ứng dụng, chiều dài có thể là chi phí hoặc giá trị khác nào đó. Chiều dài của đường đi được xác định bằng tổng chiều dài của các cung đơn trong đường đi. Với hai đỉnh bất kỳ, s và t trong G, có thể tồn tại nhiều đường đi từ s đến t. Bài toán đường đi ngắn nhất bao gồm tìm đường đi từ s đến t sao cho chiều dài nhỏ nhất có thể.

Bài toán này có thể chia làm hai loại như sau:

 Tìm đường đi ngắn nhất từ một đỉnh nguồn đến các đỉnh còn lại của đồ thị.

 Tìm đường đi ngắn nhất giữa một cặp đỉnh của đồ thị.

Đầu vào: Cho một đồ thị có hướng có trọng số G = (V, E) với V : tập đỉnh, E: tập cạnh), một hàm trọng số w:E [ 0, ∞).

Đầu ra: Hãy tìm đường đi ngắn nhất giữa hai đỉnh (chẳng hạn (s, t)) trong đồ thị G.

2.2.1.2. Thuật toán Dijkstra

Thuật toán này do nhà khoa học Hà Lan – ông Edsger Dijkstra đưa ra vào năm 1959 cung cấp nền tảng cơ bản cho thuật toán hữu hiệu nhất để giải quyết bài toán này. Thuật toán Dijkstra được thiết kế dựa trên kỹ thuật tham ăn để giải quyết bài toán tìm đường đi ngắn nhất từ một đỉnh nguồn trong đồ thị có hướng với trọng số không âm. Thuật tián Dijkstra hoạt động dựa trên việc gán nhãn cho các đỉnh.

a. Phát biểu bài toán

Đầu vào: Cho một đồ thị có hướng G = (V, E) (với V: tập đỉnh, E: tập cạnh), một hàm trọng số w: E [0,∞) và một đỉnh nguồn s

Đầu ra: Hãy tìm đường đi ngắn nhất từ tập nguồn s đến mỗi đỉnh trong đồ thị.

b. Ý tưởng chính

Giả sử đã biết k đỉnh gần đỉnh s nhất về tổng chiều dài trong đồ thị và đường đi ngắn nhất từ s đến mỗi đỉnh đó. Gán nhãn đỉnh s và k đỉnh này với khoảng cách ngắn nhất từ s. Sau đó đỉnh thứ k+1 gần đỉnh x nhất được tìm thấy như sau. Với mỗi đỉnh được gán nhãn y, xây dựng k đường đi phân biệt từ s đến y bằng cách kết nối đường đi ngắn nhất từ s đến x với cung (x, y) cho tất các đỉnh x đã được gán nhãn. Chọn đường đi ngắn nhất trong k đường đi này và đặt nó là đường đi ngắn nhất từ s đến y.

Vì vậy, nếu đã biết đỉnh thứ k gần đỉnh s nhất thì đỉnh thứ k+1 có thể được xác định như trên. Bắt đầu với k=0, quá trình này có thể lặp đi lặp lại cho đến khi tìm ra đường đi ngắn nhất từ s đến t (tức là t đã được gán nhãn).

c. Thuật toán

Thuật toán Dijsktra được thực hiện như sau:

Bước 1

 Ban đầu tất cả các cung và các đỉnh chưa được gán nhãn.

 Với mỗi đỉnh x ∈ V, gọi d(x) là nhãn được gán cho mỗi đỉnh x là độ dài đường đi ngắn nhất từ s đến x.

 Khởi tạo, đặt d(s) = 0 và d(x) = ∞ cho mọi đỉnh x ≠ s.

 Gọi y là đỉnh cuối cùng được gán nhãn.

 Gán nhãn đỉnh s và đặt y = s.

Bước 2

 Với mỗi đỉnh chưa được gán nhãn x, tính lại nhãn d(x) như sau: d(x) = min { d(x), d(y) + a(x, y)}

 Nếu d(x) = ∞ với mọi đỉnh x chưa gán nhãn thì dừng lại vì không tồn tại đường đi từ s đến đỉnh bất kỳ chưa gán nhãn.

 Ngược lại:

 Gán nhãn cho đỉnh x chưa gán nhãn với giá trị d(x) nhỏ nhất.

 Gán nhãn cho cung có hướng đến đỉnh x từ đỉnh đã được gán nhãn với giá trị d(x) ở trên. (adsbygoogle = window.adsbygoogle || []).push({});

 Đặt y = x.

Bước 3

 Nếu đỉnh t đã được gán nhãn thì dừng, vì đường đi ngắn nhất từ s đến t đã được tìm ra. Đường đi này chứa đường đi đơn của các cung đã được gán nhãn từ s đến t.

 Nếu đỉnh t chưa được gán nhãn thì lặp lại bước 2.

Chú ý rằng bất cứ khi nào thuật toán gán nhãn cho đỉnh (ngoại trừ đỉnh s) thì cũng gán nhãn cho cung hướng về đỉnh này. Vì vậy, mỗi đỉnh có tối đa một cung đã được gán nhãn hướng vào nó và các cung đã được gán nhãn

không có chu trình vì không có cung nào được gán nhãn nếu cả hai điểm đầu cuối có cung đã được gán nhãn tạo thành một dạng cây có gốc tại s đến bất kỳ điểm x nào khác nằm trong cây đường đi ngắn nhất là đường đi ngắn nhất từ s đến x.

Nếu đường đi ngắn nhất từ s đến x trong cây đường đi ngắn nhất đi qua đỉnh y thì phần đường đi từ y đến x này là đường đi ngắn nhất từ y đến x.

Ngược lại tồn tại đường đi khác thậm chí còn ngắn hơn đường đi từ y đến x, điều này mâu thuẫn với đường đi ngắn nhất từ s đến x đã tìm ra.

Vì các cung đã được gán nhãn luôn luôn tạo thành cây nên có thể xem thuật toán này như phát triển một cây có gốc tại đỉnh s. Một khi đến được đỉnh t thì có thể kết thúc quá trình phát triển.

d. Mở rộng thuật toán

Nếu muốn tìm đường đi ngắn nhất từ đỉnh s đến mọi đỉnh khác trong đồ thị thì tiếp tục quá trình phát triển cho đến khi tất cả các đỉnh được nằm trong cây đường đi ngắn nhất. Trong trường hợp này, cây trở thành cây mở rộng (nếu cây tồn tại). Khi đó bước 3 sẽ là:

Bước 3

 Nếu tất cả các đỉnh đã được gán nhãn thì dừng lại vì đường đi duy nhất của các cung đã được gán nhãn từ s đến x là đường đi ngắn nhất từ s đến x với mọi đỉnh x.

 Ngược lại, trở về bước 2.

e. Ví dụ minh hoạ

Tìm đường đi ngắn nhất từ nút s đến nút t trong đồ thị G trong hình 2.2 bằng thuật toán Dijkstra

Hình 2.2 Đồ thị minh hoạ thuật toán Dijkstra Bước 1: Khởi tạo, d(s) = 0, d(x) = ∞ với mọi x ≠ s. Đặt y = s.

Bước 2: Tính lại khoảng cách cho các nút chưa gán nhãn: d(1) = min{ d(1), d(s) + a(s, 1)} = min {∞, 0 + 4} = 4 d(2) = min { d(2), d(s) + a(s, 2)} = min {∞, 0 + 7} = 7 d(3) = min {d(3), d(s) + a(s, 3)} = min {∞, 0 + 3} = 3

Vì khoảng cách nhỏ nhất trong các nút chưa gán nhãn là d(3) = 3 nên gán nhãn cho nút 3 và cung (s, 3). Cây đường đi ngắn nhất hiện tại chứa cung (s, 3). Đặt y = 3.

Bước 3: Nút t chưa được gán nhãn nên quay lại bước 2.

Bước 2: Tính d(4) = min{d(4), d(3) + a(3, 4) } = min {∞, 3 + 3} = 6 Khoảng cách nhỏ nhất trong các nút chưa gán nhãn là d(1) = 4 nên gán nhãn cho nút 1 và cung (s, 1). Cây đường đi ngắn nhất hiện tại chứa cung (s, 3) và (s, 1). Đặt y = 1.

Bước 3: Đỉnh t chưa được gán nhãn nên quay lại bước 2

Bước 2: Tính d(2) = min{d(2), d(1) + a(1, 2)} = min {7, 4 + 3} = 7 d(4) = min{d(4), d(1) + a(1, 4)} = min {6, 4 + 2} = 6

Khoảng cách nhỏ nhất trong các nút chưa gán nhãn là d(4) = 6 nên gán nhãn cho nút 4 và cung (1, 4) hoặc (3, 4) vì cả hai đều bằng d(4).

Chọn tuỳ ý cung (3, 4). Khi đó, cây đường đi ngắn nhất chứa cung (s, 3), (s, 1) và (3, 4). Đặt y = 4.

Bước 3: Đỉnh t chưa được gán nhãn nên quay lại bước 2.

Bước 2: Tính d(t) = min {d(t), d(4) + a(4, t)} = min {∞, 6 + 2} = 8 Khoảng cách nhỏ nhất trong các nút chưa gán nhãn là d(2) = 7 nên gán nhãn cho nút 2 và cung (s, 2). Đường đi ngắn nhất hiện tại chứa cung (s, 3), (s, 1), (3, 4) và (s, 2). Đặt y = 2.

Bước 3: Đỉnh t chưa được gán nhãn nên quay lại bước 2.

Bước 2: Tính d(t) = min {d(t), d(2) + a(2, t)} = min {8, 7 + 2} = 8 Khi đó, nút t được gán nhãn cuối cùng và cung (4, t) cũng được gán nhãn là d(t). Do vậy, đường đi ngắn nhất cuối cùng chứa các cung (s, 3), (s, 1), (3, 4), (s, 2) và (4, t).

Đường đi ngắn nhất từ s đến t chứa các cung (s, 3), (3, 4) và (4, t) với chiều dài là 3 + 3 + 2 = 8. Đường đi này không chỉ là đường đi ngắn nhất duy nhất từ s đến t vì đường đi (s, 1), (1, 4) và (4, t ) cũng có chiều dài bằng 8. (adsbygoogle = window.adsbygoogle || []).push({});

2.2.1.3. Thuật toán Bellman-Ford

Ban đầu, giả sử rằng tất cả chiều dài của các cung là không âm. Nếu một số chiều dài cung là âm thì điều gì sẽ xảy ra? Ví dụ, xét đồ thị trong hình 2.2. Đường đi ngắn nhất từ đỉnh s đến đỉnh t là (s, 1), (1, t), chiều dài của nó là +2 – 2 = 0. Có thể dễ dàng nhận thấy rằng nếu thuật toán tìm đường đi ngắn nhất Dijkstra được áp dụng trong đồ thị này thì đường đi (s, t) được chọn nhầm là đường đi ngắn nhất từ đỉnh s đến đỉnh t. Vì vậy, không đảm bảo rằng thuật toán tìm đường đi ngắn nhất Dijkstra sẽ sinh ra đường đi ngắn nhất khi chiều dài cung được cho phép là âm.

Hình 2.3 Đồ thị minh họa thuật toán Bellman-Ford

1

2 -2

Thuật toán Bellman-Ford (1956) là một thuật toán tính các đường đi ngắn nhất nguồn đơn trong một đồ thị có hướng có trọng số (trong đó một số cung có thể có trọng số âm). Thuật toán Dijkstra giải cùng bài toán này với thời gian chạy thấp hơn, nhưng lại đòi hỏi trọng số của các cung phải có giá trị không âm. Do đó, thuật toán Bellman-Ford thường chỉ được dùng khi có các cung với trọng số âm.

a. Mô tả thuật toán

function BellmanFord(danh_sách_đỉnh, danh_sách_cung, nguồn)

/* hàm yêu cầu đồ thị đưa vào dưới dạng một danh sách đỉnh, một danh sách cung

hàm tính các giá trị khoảng_cách đỉnh_liền_trước của các đỉnh, sao cho các giá trị đỉnh_liền_trước sẽ lưu lại các đường đi ngắn nhất*/

//bước 1: khởi tạo đồ thị

for each v in danh_sách_đỉnh:

if v is nguồn then khoảng_cách(v) := 0

else khoảng_cách(v) := vô cùng

đỉnh_liền_trước(v) := null

// bước 2: kết nạp cạnh

for i from 1 to size(danh_sách_đỉnh):

for each (u,v) in danh_sách_cung:

if khoảng_cách(v) > khoảng_cách(u) + trọng_số(u,v) then

khoảng_cách(v) := khoảng_cách(u) + trọng_số(u,v) đỉnh_liền_trước(v) := u

// bước 3: kiểm tra chu trình âm

for each (u,v) in danh_sách_cung:

error "Đồ thị chứa chu trình âm"

2.2.1.4. Thuật toán A*

Thuật toán A* được mô tả lần đầu vào năm 1968 bởi Peter Hart, Nils Nilsson, và Bertram Raphael. Trong bài báo của họ, thuật toán được gọi là thuật toán A; khi sử dụng thuật toán này với một đánh giá heuristic thích hợp sẽ thu được hoạt động tối ưu, do đó mà có tên A*. Thuật toán A* (đọc là A sao) là một thuật toán tìm kiếm trong đồ thị. Thuật toán này tìm một đường đi từ một nút khởi đầu tới một nút đích cho trước (hoặc tới một nút thỏa mãn một điều kiện đích). Thuật toán này sử dụng một "đánh giá heuristic" để xếp loại từng nút theo ước lượng về tuyến đường tốt nhất đi qua nút đó. Thuật toán này duyệt các nút theo thứ tự của đánh giá heuristic này. Do đó, thuật toán A* là một ví dụ của tìm kiếm theo lựa chọn tốt nhất (best-first search).

a. Ý tưởng trực quan

Xét bài toán tìm đường - bài toán mà A* thường được dùng để giải. A* xây dựng tăng dần tất cả các tuyến đường từ điểm xuất phát cho tới khi nó tìm thấy một đường đi chạm tới đích. Tuy nhiên, cũng như tất cả các thuật toán tìm kiếm có thông tin, nó chỉ xây dựng các tuyến đường "có vẻ" dẫn về phía đích. Để biết những tuyến đường nào có khả năng sẽ dẫn tới đích, A* sử dụng một "đánh giá heuristic" về khoảng cách từ điểm bất kỳ cho trước tới đích. Trong trường hợp tìm đường đi, đánh giá này có thể là khoảng cách đường chim bay - một đánh giá xấp xỉ thường dùng cho khoảng cách của đường giao thông.

Điểm khác biệt của A* đối với tìm kiếm theo lựa chọn tốt nhất là nó còn tính đến khoảng cách đã đi qua. Điều đó làm cho A* "đầy đủ" và "tối ưu", nghĩa là, A* sẽ luôn luôn tìm thấy đường đi ngắn nhất nếu tồn tại một đường đi như thế. A* không đảm bảo sẽ chạy nhanh hơn các thuật toán tìm kiếm đơn giản hơn. Trong một môi trường dạng mê cung, cách duy nhất để đến đích có thể là trước hết phải đi về phía xa đích và cuối cùng mới quay lại. Trong

trường hợp đó, việc thử các nút theo thứ tự "gần đích hơn thì được thử trước" có thể gây tốn thời gian.

b. Mô tả thuật toán (adsbygoogle = window.adsbygoogle || []).push({});

Thuật toán A* dựa trên thuật toán Dijkstra, vì vậy cũng như Dijkstra, tư tưởng tìm đường của A* dựa trên chiến lược tìm kiếm theo chiều rộng. Trước khi xem xét thuật toán , ta quy ước cho bà i toán tìm đư ờng đi ngắn nhất trên đồ thị G:

- s = đỉnh xuất phát. - t = đỉnh kết thúc.

- close = tập các đỉnh đã được tính toán chính xác đường đi ngắn nhất. - open = tập các đỉnh còn lại.

- s(i,j) = trọng số của cung (i,j).

- d(i) = khoảng cách nhỏ nhất từ i đến s.

- v(i) = khoảng cách min ước lượng từ i đến s.

Khi đó, nhiệm vụ đầu tiên của các thuật toán tìm đư ờng đi ngắn nhất là phải tìm được giá trị d(t).

Mô phỏng chi tiết thuật toán A* như sau: d(i) = + ∞với ∀i ∈ [1..n]

close = [s]

open = [1..n] – [s] k = s

repeat

{sửa đổi ước lượng min} Với ∀i ∈ open

d(i) = min {d(i), d(k) + a(k, i)} {mở rộng tập close}

open = open – [k] close = close + [k] Until (t ∈ close) ;

c. Thuật toán A* sử dụng đánh giá hàm heuristic

Đánh giá hàm heuristic có thể dùng để kiểm soát trạng thái của thuật toán A*: Ở một mức độ nào đó, nếu hàm h(n) = 0 thì f(n) = g(n), thuật toán A* bây giờ là thuật toán Dijkstra, vẫn đảm bảo tìm kiếm đường đi ngắn nhất. Nếu h(n) ≤ chi phí di chuyển từ n đến đích, A* đảm bảo tìm kiếm đường đi ngắn nhất; h(n) càng nhỏ, thuật toán A* càng được mở rộng, tạo ra chi phí nhỏ hơn. Nếu h(n) = chi phí di chuyển đến đích (điểm mục tiêu) A* sẽ là đường đi ngắn nhất và không bao giờ mở rộng hơn nữa, thời gian nhanh hơn. Mặc dù không thể thực hiện điều này trong tất cả các trường hợp, nhưng có thể tạo sự chính xác trong một vài trường hợp đặc biệt. Tốt cho việc biết được đầy đủ các thông tin khi đó A* đầy đủ hơn. Nếu h(n) lớn hơn chi phí di chuyển từ n đến đích, A* không đảm bảo sẽ tìm được đường đi ngắn nhất nhưng nó có thể tốn ít thời gian hơn (chạy nhanh hơn).

Trong một chừng mực nào đó, nếu h(n) quá lớn so với g(n), khi đó f(n), h(n), khi đó A* trở thành BFS (best - first search).

Chú ý: về mặt kỹ thuật mà nói, thuật toán A* có thể gọi đơn giản là thuật toán A nếu Heuristic là một đánh giá thấp hơn chi phí thực tế. Tuy nhiên, có thể gọi A* bởi vì việc thực hiện hoàn toàn giống nhau và những chương trình game thì không phân biệt A hay A*. Trong trường hợp này, chúng ta có một tình huống khá là thú vị là chúng ta có thể quyết định cái gì chúng ta muốn thoát khỏi A*. Chính xác hơn là tại một điểm xác định, chúng ta sẽ tìm được đường đi ngắn nhất rất nhanh. Nếu chúng ta quá chậm, sau đó tiếp tục tìm kiếm đường đi ngắn nhất, và nó sẽ nhanh hơn. Nếu nó quá lớn, chúng ta có thể bỏ qua đường đi ngắn nhất và A* sẽ nhanh hơn. Trong trò

chơi, đặc tính này của A* có thể rất hữu dụng. Ví dụ, chúng ta có thể tìm thấy trong một số tình huống, chúng ta sẽ có đường đi “good” hơn là đường đi “path”. Để cân bằng giữa g(n) và h(n) chúng ta có thể thay đổi cả hai.

d. Tính nhanh chóng và độ chính xác

Khả năng của A* khác nhau là dựa cơ bản vào đánh giá heuristic và hàm chi phí có thể có ích trong một bài toán. Việc cân bằng giữa tính nhanh chóng và độ chính xác có thể được xem là một kỳ công làm cho trò chơi nhanh hơn. Đối với hầu hết các games hay bài toán, chúng ta không thực sự cần thiết giữa 2 điểm có đường đi ngắn nhất. Chúng ta chỉ cần vài điều mang

Một phần của tài liệu nghiên cứu một số thuật toán trong gis ứng dụng logic mờ (Trang 46)