Họ và tên:Vũ Khắc Điệp-Tin 5a GIẢI THUẬT TÌM KIẾM A* Trong khoa học máy tính, A* (A* Search) là 1 thuật toán tìm kiếm trong đồ thị. Thuật toán này tìm một đường đi từ 1 nút khởi đầu tới 1 nút cho trước (hoặc tới 1 nút thỏa mãn 1 điều kiện đích). Thuật toán này sử dụng 1 đá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 thưo thứ tự của đánh giá heurristic này. Do đó thuật toán A* là 1 ví dụ của tìm kiếm theo lựa chọn tốt nhất (best – first- search). Thuật toán A* được mô tả lần đầu vào năm 1968 bở Peter Hart và Bertram Rafael. 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 1 đánh giá heuristic thích hợp sẽ thu được hoạt động tối ưu, do đó mà có tên là A*. I.Heuristic chấp nhận được Trong kỹ thuật tìm kiếm, để việc tìm kiếm có hiệu quả sẽ sử dụng hàm đánh giá để hướng dẫn tìm kiếm. Các kỹ thuật này thuộc nhóm tìm kiếm Heuristic. • Giả sử u là một trạng thái đạt tới (có đường đi từ trạng thái đầu u0 tới u); hàm đánh giá được xác định như sau: g(u): đánh giá độ dài đường đi ngắn nhất từ u0 tới u. h(u): đánh giá độ dài đường đi ngắn nhất từ u tới trạng thái đích.Hàm h(u) được gọi là chấp nhận được nếu với mọi trạng thái u, h(u) ≤ độ dài đường đi ngắn nhất thực tế từ u tới trạng thái đích. Để tăng hiệu quả của quá trình tìm kiếm: f(u) = g (u) + h(u) • Heuristic chấp nhận được trong A* Heuristic h(n) là chấp nhận được nếu với mọi node n, h(n) ≤ h*(n), trong đó h*(n) là chi phí thực để đi đến đích từ n. Heuristic chấp nhận được không bao giờ đánh giá chi phí cao quá thực tế. Định lý: Nếu h(n) là chấp nhận được, A* là thuật toán cho lời giải tối ưu. II.Ý TƯỞNG Xét bài toán tìm đường - bài toán mà A* thường
Trang 1HỌC VIỆN KỸ THUẬT QUÂN SỰ KHOA CÔNG NGHỆ THÔNG TIN
BÁO CÁO MÔN HỌC
TRÍ TUỆ NHÂN TẠO
Giáo viên hướng dẫn: Ngô Hữu Phúc
HÀ NỘI 3/2010
Trang 2Họ và tên:Vũ Khắc Điệp-Tin 5a
GIẢI THUẬT TÌM KIẾM A*
Trong khoa học máy tính, A* (A* Search) là 1 thuật toán tìm kiếm trong đồ thị Thuật toán này tìm một đường đi từ 1 nút khởi đầu tới 1 nút cho trước (hoặc tới 1 nút thỏa mãn 1 điều kiện đích) Thuật toán này sử dụng 1 đá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 thưo thứ tự của đánh giá heurristic này Do đó thuật toán A* là 1 ví dụ của tìm kiếm theo lựa chọn tốt nhất (best – first- search).
Thuật toán A* được mô tả lần đầu vào năm 1968 bở Peter Hart và Bertram Rafael 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
1 đánh giá heuristic thích hợp sẽ thu được hoạt động tối ưu, do đó mà có tên là A*.
I.Heuristic chấp nhận được
Trong kỹ thuật tìm kiếm, để việc tìm kiếm có hiệu quả sẽ sử dụng hàm đánh giá để hướng dẫn tìm kiếm Các kỹ thuật này thuộc nhóm tìm kiếm Heuristic.
Giả sử u là một trạng thái đạt tới (có đường đi từ trạng thái đầu u
0 tới u); hàm đánh giá được xác định như sau:
g(u): đánh giá độ dài đường đi ngắn nhất từ u 0 tới u.
h(u): đánh giá độ dài đường đi ngắn nhất từ u tới trạng thái
đích.Hàm h(u) được gọi là chấp nhận được nếu với mọi trạng thái u, h(u) ≤ độ dài đường đi ngắn nhất thực tế từ u tới trạng thái đích.
Để tăng hiệu quả của quá trình tìm kiếm: f(u) = g (u) + h(u)
Heuristic chấp nhận được trong A*
Trang 3 Heuristic h(n) là chấp nhận được nếu với mọi node n, h(n) ≤ h * (n),
trong đó h * (n) là chi phí thực để đi đến đích từ n.
Heuristic chấp nhận được không bao giờ đánh giá chi phí cao quá thực tế.
Định lý : Nếu h(n) là chấp nhận được, A * là thuật toán cho lời giải tối ưu.
II.Ý TƯỞNG
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 phương pháp tìm kiếm có sử dụng 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 BFS 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.
III.MÔ TẢ THUẬT TOÁN
Trang 4A* lưu giữ một tập các lời giải chưa hoàn chỉnh, nghĩa là các đường đi qua đồ thị, bắt đầu từ nút xuất phát Tập lời giải này được lưu trong một hàng đợi ưu tiên (priority
queue) Thứ tự ưu tiên gán cho một đường đi n được quyết định bởi hàm lượng giá f(n)=
g(n) + h(n)
g(n) = chi phí để đến n
h(n)= lượng giá từ n đến đích
f(n)= ước lượng tổng giá đến đích qua n
Procedure A*;
Begin
1 Khởi tạo danh sách L chỉ chứa trạng thái đầu.
2 Loop do
2.1 if L rỗng then {thông báo thất bại; stop;}
2.2 Loại trạng thái u ở đầu danh sách L;
2.3 if u là trạng thái đích then {thông báo thành công; stop}
2.4 for mỗi trạng thái v kề u do
{ g(v) ← g(u)+ k(u,v); f(v) ← g(v)+h(v);
Đặt v vào danh sách L;}
2.5 Sắp xếp L theo thứ tự giảm dần của hàm f sao cho trạng thái có giá trị của hàm f nhỏ nhất ở đầu danh sách;
3.END
IV.Chương trình DEMO
a.Giao diện chương trình
Trang 5Gồm các phần:
Vẽ Điểm
Vẽ cạnh
Xóa
Thuật toán A*
Thoát
1.Vẽ điểm
Ta CLIKC chuột và chọn các điểm bất kỳ
Trang 62.Vẽ cạnh
Ta click chuột vào vẽ cạnh và chọn các điểm 1-2,1-3, 4-10
Trang 7Nếu chọn nhầm điểm và cạnh,ta có thể xóa và bắt đầu lại chương trình
từ đầu với các lần chọn điểm và cạnh
4.Thuật toán A*
Sau khi chọn điểm và cạnh xong,ta chọn điểm đầu và điểm cuối, ta click chuột vào Thuật toán A*
Ra kết quả
Trang 8Dùng để thoát chương trình
b.Các hàm xử lý
1.Hàm khởi tạo
private void Init()
{
int i;
int j;
buoc = 0;
VeDiem = false;
VeDoanThang = false;
cmbDiemDau.Items.Clear();
cmbDiemCuoi.Items.Clear();
diem = false;
graph = panel1.CreateGraphics();
_PointNo = 0;
Trang 9Canh = new int[1000, 1000];
for (i = 0; i < 1000; i++)
for (j = 0; j < 1000; j++)
{
if (i == j)
Canh[i, j] = 0;
else Canh[i, j] = -1;
}
h = new int[1000];
g = new int[1000];
f = new int[1000];
father = new int[1000];
ChuaXet = new bool[1000];
Queue = new int[1000];
QueueNo = 0;
for (i = 0; i < 1000; i++)
{
father[i] = 0;
ChuaXet[i] = true;
}
DaTimThay = false;
rtxtQueue.Text = "";
2.Hàm vẽ điểm
private void DrawPoint(int x, int y)
{
_PointNo += 1;
cmbDiemCuoi.Items.Add(_PointNo.ToString());
cmbDiemDau.Items.Add(_PointNo.ToString());
20, 20);
graph.DrawString(_PointNo.ToString(), new
false), Brushes.White, x - 6, y - 6);
}
3.Hàm tìm điểm
private int TimDiem(int x, int y)
{
int i;
for (i = 1; i <= _PointNo; i++)
{
if ((x > _Points[i].X - 10) && (x < _Points[i].X + 10) && (y > _Points[i].Y - 10) && (y < _Points[i].Y + 10))
return i;
Trang 10}
return 0;
4.Hàm tìm điểm và nối các điểm bằng sự kiện
private void panel1_MouseClick(object sender, MouseEventArgs e)
{
int i;
int kc;
if (VeDiem == true)
{
DrawPoint(e.X, e.Y);
}
else if (VeDoanThang == true)
{
if (diem == false)
{
i = TimDiem(e.X, e.Y);
if (i > 0)
{
idau = i;
_Points[i].X - 10, _Points[i].Y - 10, 20, 20);
graph.DrawString(i.ToString(), new
false), Brushes.White, _Points[i].X - 6, _Points[i].Y - 6);
diem = true;
}
}
else
{
i = TimDiem(e.X, e.Y);
if (i>0)
{
dau.X - 10, dau.Y - 10, 20, 20);
graph.DrawString(idau.ToString(), new
false), Brushes.White, dau.X - 6, dau.Y - 6);
cuoi.X) + (dau.Y - cuoi.Y) * (dau.Y - cuoi.Y)) / 10;
graph.DrawString(kc.ToString(), new
false), Brushes.Red, (dau.X + cuoi.X) / 2, (dau.Y + cuoi.Y) / 2);
diem = false;
Canh[idau, i] = kc;
Canh[i, idau] = kc;
}
Trang 11}
}
}
5.Hàm trả về kết quả tìm kiếm
private void KetQua(int vitri)
{
int i;
int kc;
string duongdi = "";
kc = f[vitri];
i = vitri;
duongdi += DiemCuoi.ToString();
while (Queue[i] != DiemDau)
{
_Points[Queue[father[i]]]);
if (Queue[i]!=DiemCuoi)
duongdi = Queue[i].ToString() + " > " + duongdi;
i = father[i];
}
duongdi ="Đường đi: "+ DiemDau.ToString() + " > " + duongdi; rtxtQueue.Text +=duongdi+ "\r\nĐộ dài đường đi: " +
kc.ToString();;
10, _Points[DiemDau].Y - 10, 20, 20);
-10, _Points[DiemCuoi].Y - -10, 20, 20);
graph.DrawString(DiemDau.ToString(), new
false), Brushes.White, _Points[DiemDau].X - 6, _Points[DiemDau].Y - 6);
graph.DrawString(DiemCuoi.ToString(), new
false), Brushes.White, _Points[DiemCuoi].X - 6, _Points[DiemCuoi].Y - 6);
}
6.Hàm sắp xếp vị trí trong danh sách L
private void SapXep()
{
int tg;
for (int i=vt+1;i<QueueNo;i++)
for (int j=i+1;j<=QueueNo;j++)
if (f[i] > f[j])
{
tg = f[i]; f[i] = f[j]; f[j] = tg;
tg = Queue[i]; Queue[i] = Queue[j]; Queue[j] = tg;
tg = father[i]; father[i] = father[j]; father[j] =tg;
Trang 12tg = g[i]; g[i] = g[j]; g[j] = tg;
}
}
7.Hàm xủ lí thuật toán A*
private void AStar()
{
int u;
int i;
int tempg;
int tempf;
if (DaTimThay == false)
{
if (vt <= QueueNo)
{
u = Queue[vt];
if (u == DiemCuoi)
{
DaTimThay = true;
KetQua(vt);
}
else
{
tempg = g[vt];
tempf = f[vt];
for (int v = 1; v <= _PointNo; v++) {
if (Canh[u, v] > 0)
{
QueueNo += 1;
Queue[QueueNo] = v;
g[QueueNo] = tempg + Canh[u, v]; f[QueueNo] = g[QueueNo] + h[v]; father[QueueNo] = vt;
}
}
SapXep();
vt += 1;
}
}
if (vt<=QueueNo)
AStar();
}
}
8.Hàm vẽ đồ thị
Trang 13private void DrawDoThi()
{
int i;
int j;
int kc;
panel1.Refresh();
for (i = 1; i <= _PointNo; i++)
for (j = 1; j <= _PointNo; j++)
if (Canh[i, j] > 0)
{
_Points[j]);
(_Points[i].X - _Points[j].X) + (_Points[i].Y - _Points[j].Y) * (_Points[i].Y
- _Points[j].Y)) / 10;
graph.DrawString(kc.ToString(), new
false), Brushes.Red, (_Points[i].X + _Points[j].X) / 2, (_Points[i].Y +
_Points[j].Y) / 2);
}
for (i = 1; i <= _PointNo; i++)
{
10, 20, 20);
10, _Points[i].Y - 10, 20, 20);
graph.DrawString(i.ToString(), new
false), Brushes.White, _Points[i].X - 6, _Points[i].Y - 6);
}
if (cmbDiemCuoi.SelectedIndex >= 0)
{
for (i = 1; i <= _PointNo; i++)
{
* (_Points[i].X - _Points[DiemCuoi].X) + (_Points[i].Y - _Points[DiemCuoi].Y)
* (_Points[i].Y - _Points[DiemCuoi].Y)) / 10;
graph.DrawString(h[i].ToString(), new
false), Brushes.Black, _Points[i].X - 10, _Points[i].Y - 23);
}
}
}