1. Trang chủ
  2. » Công Nghệ Thông Tin

Bài toán đô thị thông minh

7 206 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 7
Dung lượng 46,5 KB

Nội dung

Thuật toán A* tìm đường đi ngắn nhất trên đồ thị có thông tin định hướngNguyễn Văn Sơn Để giải bài toán tìm đường đi trên đồ thị chúng ta có rất nhiều thuật toán như Dijkstra, thuật toán

Trang 1

Thuật toán A* tìm đường đi ngắn nhất trên đồ thị có thông tin định hướng

Nguyễn Văn Sơn

Để giải bài toán tìm đường đi trên đồ thị chúng ta có rất nhiều thuật toán như Dijkstra, thuật toán Floy-Bellman Trong bài viết này, chúng tôi giới thiệu với bạn đọc một thuật toán nổi tiếng tìm đường đi ngắn nhất trên đồ thị có thông tin định hướng với tên gọi A* (đọc là ″a sao″)

Thuật toán này dựa trên tư tưởng tìm kiếm heuristic được áp dụng vào những bài toán trong thực tế với với các thông tin đặc biệt được bổ sung ví dụ như: có thể tồn tại một cung với trọng số lớn hơn tổng trọng số của các cung còn trên đồ thị, hoặc một đồ thị không có cung nào Thuật toán A* đặc biệt có hiệu quả khi áp dụng vào những bài toán

có kích thước lớn như bài toán tìm đường trong một mạng lưới giao thông có nhiều nút, bài toán tìm đường đi trong các trò chơi chiến thuật với nhiều vật cản Điểm mấu chốt trong quá trình cài đặt thuật toán là việc xác định chính xác thông tin ước lượng nhằm định hướng cho việc tìm kiếm Chẳng hạn, trong bài toán tìm đường đi trong thành phố thì thông tin ước lượng cho phép tìm ra đường tắt và tránh những vị trí hay bị tắc nghẽn; còn trong các chương trình trò chơi, nó có thể định hướng đi tới đích nhanh nhất, nếu gặp vật cản thì đi men theo vật cản

Nội dung thuật toán được trình bày như dưới đây:

Một số ký hiệu:

- s: đỉnh xuất phát

- t: đỉnh kết thúc (đích)

- close: tập các đỉnh đã được tính chính xác đường đi ngắn nhất

- open: tập các đỉnh còn lại

- l[i,j]: trọng số của cung (i,j)

- d[i]: khoảng cách ngắn nhất từ i đến s

- v[i]: khoảng cách ngắn nhất ước lượng từ i đến s

Yêu cầu của bài toán là cần tìm giá trị của d[t]

Thuật toán A*

d[i] = +∞ i với mọi i thuộc [1 n]

close= [s]

open= [1 n] − [s]

k = s

repeat

{sửa đổi ước lượng min}

với mọi i thuộc open

d[i] = min {d[i], d[k] +l[k,i]}

{mở rộng tập close}

chọn k thuộc open để

(d[k] + v[k] ≤ d[i] + v[i]) với với mọi i thuộc open

open = open − [k]

close = close + [k]

until t thuộc close;

Trang 2

Thuật toán Dijkstra d[i] = +∞với mọi i thuộc [1 n]

close= [s]

open= [1 n] − [s]

k = s

repeat

{sửa đổi ước lượng min}

với mọi i thuộcopen

d[i] = min {d[i], d[k] +l[k,i]}

{mở rộng tập close}

chọn k thuộc open để

(d[k] ≤ d[i] ) vớivới mọi i thuộcopen

open = open − [k]

close = close + [k]

until t thuộc close;

Sự khác biệt duy nhất của hai thuật toán ở điểm chọn đỉnh k để mở rộng tập close Việc lựa chọn đỉnh nào để mở rộng cho quá trình tìm kiếm đóng vai trò rất quan trọng trong chiến lược tìm kiếm Nếu ta lựa chọn được đỉnh để phát triển tiếp với các ước lượng tốt

có thể rút ngắn thời gian và chi phí tính toán Cả hai thuật toán ở trên đều có độ phức tạp

là O(n2) Người ta đã chứng minh được rằng nếu các trọng số của đồ thị đều là dương (l[i,j]>0 với mọi i,j) và v[i] là ước lượng dương bé hơn so với đường đi ngắn nhất từ i tới

u (0< v[i] <d[i] với mọi i), thì thuật toán A* luôn tối ưu hơn thuật toán Dijkstra về mặt thời gian và cho ra kết quả chính xác Dễ có nhận xét rằng nếu v[i] = 0 thì thuật toán n A* trở thành thuật toán Dijkstra

Vấn đề mấu chốt nhất khi xây dựng thuật toán A* cho các ứng dụng thực tế là việc tìm ra hàm ước lượng v[i] Sau đây chúng ta xem xét vài ví dụ đơn giản Hãy xây dựng các ước lượng cho thuật toán A* với bài toán chỉ ra đường đi ngắn nhất của một quân cờ di chuyển trên một bàn cờ có kích thước vô tận và có một số ô được đánh dấu không được

đi vào Chúng ta cần xây dựng v(x1,y1,x2,y2) là ước lượng của đường đi ngắn nhất từ ô (x1,y1) tới ô (x2,y2) Việc xây dựng hàm này phụ thuộc vào quân cờ mà chúng ta xét tới

là loại gì Dưới đây là minh hoạ về hàm lượng giá cho một số loại quân:

Với loại quân cờ chỉ có thể dịch chuyển một bước sang một trong bốn ô chung cạnh với ô

mà nó đang đứng, thì v(x1,y1,x2,y2)= | x1− x2 | +| y1 − y2 |

Với loại quân cờ chỉ có thể dịch chuyển một bước sang một trong tám ô chung cạnh với ô

mà nó đang đứng (ví dụ quân Vua trong cờ vua), thì v(x1,y1,x2,y2)= Max (| x1− x2 |,| y1

− y2 |)

Với loại quân cờ chỉ có thể dịch chuyển một bước sang một trong tám ô chéo 1/2 với ô

mà nó đang đứng (ví dụ quân Mã trong cờ vua), thì v(x1,y1,x2,y2)= (| x1− x2 | +| y1 − y2

|)/4

Dễ thấy, những ước lượng này đều thoả mãn tiêu chuẩn để thuật toán A*cho nghiệm đúng, tức là chúng đều là các đánh giá thấp của đường đi ngắn nhất Trong các trò chơi thực tế, thông thường người ta sử dụng các biến thể của thuật toán A* và khi đó hàm ước lượng thường rất phức tạp

Sau đây chúng ta cùng xem xét một trò chơi phổ biến và khá đơn giản sau (trò chơi 8 − puzzle):

Có 8 số mang các giá trị từ 1 tới 8 được sắp xếp vào một bảng các ô vuông kích thước 3x3 Mỗi số đó được xếp vào một ô, có một ô của bảng bỏ trống Cho trước hai bảng các

Trang 3

con số (thể hiện cho trạng thái nguồn và trạng thái đích của bài toán), hãy chỉ ra một dãy các phép chuyển các con số (nếu có) để thu được một một bảng (trạng thái đích) từ bảng còn lại (trạng thái nguồn) Bạn chỉ được phép chuyển các con số sang một tron bốn ô chung cạnh còn trống

Trong bài toán này, ta sử dụng hàm đánh v với ý nghĩa: v(u) cho biết số các chữ số trong trạng thái u không trùng với vị trí của nó trong trạng thái đích

- Chương trình nguồn minh hoạ cho thuật

toán -{$B-}{$M 65000,0,655360}

Uses Crt;

Const Max=6;

fi='SO.INP';

fo='SO.OUT';

Type Vec=Array[1 Max,1 Max] of byte;

Item=record Ma:vec;Father,child:longint; End;

Pointer =^node; Node=record Infor:item;

Next:pointer; End;

Node1=array[1 4] of vec;Tp=0 10;

Var

U :item; Id :longint;

Front,rear,top:pointer; P :node1;

Dau,dich :vec; Found :boolean;

N :2 10; So_pts :tp;

I,j :tp;

ff:text;

PROCEDURE Vi_tri(a:vec;var k,t:TP);

Var i,j:1 max;

Begin For i:=1 to n do For J:=1 to n do

If a[i,j]=0 then

Begin K:=i; T:=j; Exit; End;

End;

{minh hoa cho cac phep di chuyen so}

PROCEDURE Left(a:vec;var lef:vec;i,j:tp);

Begin A[i,j]:=A[i,j+1];A[i,j+1]:=0; Lef:=A;

End;

PROCEDURE Right(a:vec;var righ:vec;i,j:tp);

Begin A[i,j]:=A[i,j-1]; A[i,j-1]:=0; Righ:=A;

End;

PROCEDURE Up(a:vec;var u:vec;i,j:tp);

Begin A[i,j]:=A[i+1,j]; A[i+1,j]:=0; U:=A;

End;

Trang 4

PROCEDURE Down(a:vec;var dow:vec;i,j:tp);

Begin A[i,j]:=A[i-1,j];A[i-1,j]:=0;Dow:=A

End;

PROCEDURE Pop(var Top:pointer;var U:Item);

Var Q:Pointer;

Begin Q:=Top;Top:=Top^.next;U:=Q^.infor; Dispose(q) End;

PROCEDURE Ađ(u:Item;var rear,front:pointer);

Var Q:pointer;

Begin New(q); Q^.infor:=u;

Q^.next:=nil;

If front =nil then front:=q

Else rear^.next:=q;Rear:=q

End;

FUNCTION Count(a:vec):byte;

Var i,j :0 10; Dem :byte;

Begin Dem:=0; For i:=1 to n do For j:=1 to n do

If a[i,j]<>Dich[i,j] then dem:= dem+1;Count:=Dem End;

FUNCTION Dung(a,b:vec):boolean;

Var i,j:tp;

Begin Dung:=false;

For i:=1 to n do For J:=1 to n do

If a[i,j]<>b[i,j] then exit;Dung:=true;

End;

FUNCTION Ktr(Front ,top:pointer;a:vec):boolean; Var q :Pointer; Ok :boolean;

Begin Ok:=true; Q:=top;

While (q<>nil) and ok do

if Dung(Q^.infor.ma,A) then ok:=False

Else Q:=q^.next; Q:=Front;

While (q<>nil) and ok do

if Dung(Q^.infor.ma,a) then ok:=False

Else Q:=q^.next; Ktr:=ok

End;

PROCEDURE Nhap;

Var i,j:1 max;

Begin assign(ff,fi);

reset(ff);

readln(ff,n);

For i:=1 to n do

For j:=1 to n do

Read(ff,dau[i,j]);

For i:=1 to n do

For j:=1 to n do

Read(ff,dich[i,j]);

Trang 5

End;

PROCEDURE In_vec(a:vec);

Var i,j:byte;

Begin For i:= 1 to n do

Begin For j:=1 to n do

If a[i,j]<>0 then write(ff,a[i,j]:3) else write(ff,' ');

writeln(ff);

End;

End;

FUNCTION Nhap_cx(a:vec):Boolean;

Var i,j :byte; S1,s2 :Set of byte;

Begin S1:=[];s2:=[];

For I:=0 to N*N-1 do s1:=s1+[i];

Nhap_cx:=False; For i:=1 to n do

For J:=1 to n do

If not(a[i,j] in s1) or (a[i,j] in s2)then exit

Else S2:=s2+[a[i,j]];

Nhap_cx:=true;

End;

PROCEDURE Init;

Var U:pointer;

Begin Clrscr;

Nhap;

If not Nhap_cx(dau)or not Nhap_cx(dich) then

begin Writeln('LOI KHI DOC DU LIEU');

readln;

halt;

end;

Found:=false;New(U);

U^.infor.ma:=Dau;U^.infor.father:=0;

U^.infor.child:=1;U^.next:=nil;

Top:=U;front:=nil;Rear:=nil;

End;

PROCEDURE Ptu_ke(var p:node1;U:vec;i,j:tp;var so_pts:tp); Var v :vec;

Begin If I>1 then Begin Down(u,v,i,j);

If ktr(front,top,v) then

Begin So_pts:=so_pts+1; P[so_pts]:=v;End

End;

If j>1 then

Begin Right(u,v,i,j);

If ktr(front,top,v) then

Begin So_pts:=so_pts+1;P[so_pts]:=v End

End;

If j

Trang 6

If ktr(front,top,v) then

Begin So_pts:=so_pts+1; P[so_pts]:=v; End

End;

If I

If ktr(front,top,v) then

Begin So_pts:=so_pts+1;P[so_pts]:=v;End

End;

End;

PROCEDURE Sxep(Var P:node1;so_pts:tp);

Var Tg :vec; T,i,j,min :tp; B :array[1 4] of byte;

Begin For i:=1 to so_pts do B[i]:=count(p[i]);

For i:=1 to so_pts-1 do

Begin Min:=i;

For j:=i+1 to so_pts do

If b[j] If min>i then

Begin T:=b[i]; B[i]:=b[min];B[min]:=t;

Tg:=p[i];P[i]:=p[min];P[min]:=tg; End

End

End;

PROCEDURE Push(var top:pointer;p:node1;child:longint;so_pts:tp); Var i:tp;v:pointer;

Begin For i:=so_pts downto 1 do Begin

New(v); V^.infor.ma:=p[i];

V^.infor.father:=child; Id:=id+1;

V^.infor.child:=id;

V^.next:=top; Top:=v;End

End;

PROCEDURE In_Kq;

Var p :pointer;i,buoc :longint;

Begin Buoc:=0;

P:=front;I:=1;

assign(ff,fo);

rewrite(ff);

if not found then

begin

write(ff,0);

close(ff);

exit;

end;

P:=p^.next;

While P<>nil do

Begin If p^.infor.father=i then

Begin

I:=p^.infor.child; Buoc:=buoc+1;

Writeln(ff,buoc);In_vec(P^.infor.ma);

End; P:=p^.next

Trang 7

close(ff);

End;

Begin

Clrscr;Init;

While (top<>nil) and not(Found) do

Begin Pop(Top,U); Ađ(u,Rear,Front);

If dung(u.ma,dich) then found:=true

Else Begin Vi_tri(U.ma,i,j); So_pts:=0;

Ptu_ke(p,u.ma,i,j,so_pts);

sxep(p,so_pts);Push(top,p,u.child,so_pts) End

End;

In_kq;

End

Bài tập: Cho một ma trận nhị phân (các số là 0 hay 1) kích thước 500 x 500 Hai ô được

gọi là kề nhau nếu chúng cùng chứa số 0 và chung cạnh Hai ô gọi là đi được đến nhau nếu chúng có thể đi được đến nhau qua một số bước dịch chuyển qua các ô kề nhau, số bước dịch chuyển là độ dài của đường đi hãy tìm đường đi ngắn nhất từ ô (x1,y1) tới ô (x2,y2)

Ngày đăng: 06/07/2017, 14:13

TỪ KHÓA LIÊN QUAN

w