Tải bản đầy đủ (.docx) (14 trang)

Báo cáo đồ án trí tuệ nhân tạo: TÌM ĐƯỜNG ĐI VỚI GIẢI THUẬT TÌM KIẾM A*

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (367.57 KB, 14 trang )

HỌ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
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 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*
 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

A* 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
Gồ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ỳ

2.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
3.Xóa
Nế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ả
6.Thoát
Dù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;
btnVeDiem.BackColor = SystemColors.Control;
btnVeDoanThang.BackColor = SystemColors.Control;
cmbDiemDau.Items.Clear();
cmbDiemCuoi.Items.Clear();
diem = false;

graph = panel1.CreateGraphics();
_Points = new Point[1000];
_PointNo = 0;

Canh = 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;
_Points[_PointNo] = new Point(x, y);
cmbDiemCuoi.Items.Add(_PointNo.ToString());
cmbDiemDau.Items.Add(_PointNo.ToString());


graph.DrawEllipse(Pens.DarkBlue, x-10, y-10, 20, 20);
graph.FillEllipse(new SolidBrush(Color.DarkBlue), x - 10, y - 10,
20, 20);
graph.DrawString(_PointNo.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
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;
}
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)
{
dau = new Point(_Points[i].X, _Points[i].Y);
idau = i;
graph.FillEllipse(new SolidBrush(Color.DarkBlue),
_Points[i].X - 10, _Points[i].Y - 10, 20, 20);
graph.DrawString(i.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.White, _Points[i].X - 6, _Points[i].Y - 6);
diem = true;
}
}
else
{
i = TimDiem(e.X, e.Y);
if (i>0)
{
cuoi=new Point(_Points[i].X, _Points[i].Y);
graph.DrawLine(new Pen(Color.DarkBlue), dau, cuoi);
graph.FillEllipse(new SolidBrush(Color.DarkBlue),
dau.X - 10, dau.Y - 10, 20, 20);
graph.DrawString(idau.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.White, dau.X - 6, dau.Y - 6);
kc = (int)Math.Sqrt((dau.X - cuoi.X) * (dau.X -
cuoi.X) + (dau.Y - cuoi.Y) * (dau.Y - cuoi.Y)) / 10;

graph.DrawString(kc.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.Red, (dau.X + cuoi.X) / 2, (dau.Y + cuoi.Y) / 2);
diem = false;
Canh[idau, i] = kc;
Canh[i, idau] = kc;

}
}
}
}
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)
{
graph.DrawLine(new Pen(Color.Red, 3), _Points[Queue[i]],
_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();;
graph.FillEllipse(new SolidBrush(Color.Red), _Points[DiemDau].X -
10, _Points[DiemDau].Y - 10, 20, 20);
graph.FillEllipse(new SolidBrush(Color.Red), _Points[DiemCuoi].X -
10, _Points[DiemCuoi].Y - 10, 20, 20);
graph.DrawString(DiemDau.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.White, _Points[DiemDau].X - 6, _Points[DiemDau].Y - 6);
graph.DrawString(DiemCuoi.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
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;
tg = 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ị
private 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)
{
graph.DrawLine(new Pen(Color.BlueViolet), _Points[i],
_Points[j]);
kc = (int)Math.Sqrt((_Points[i].X - _Points[j].X) *
(_Points[i].X - _Points[j].X) + (_Points[i].Y - _Points[j].Y) * (_Points[i].Y
- _Points[j].Y)) / 10;
graph.DrawString(kc.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.Red, (_Points[i].X + _Points[j].X) / 2, (_Points[i].Y +

_Points[j].Y) / 2);
}
for (i = 1; i <= _PointNo; i++)
{
graph.DrawEllipse(Pens.Red, _Points[i].X - 10, _Points[i].Y -
10, 20, 20);
graph.FillEllipse(new SolidBrush(Color.Blue), _Points[i].X -
10, _Points[i].Y - 10, 20, 20);
graph.DrawString(i.ToString(), new
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.White, _Points[i].X - 6, _Points[i].Y - 6);
}

if (cmbDiemCuoi.SelectedIndex >= 0)
{
for (i = 1; i <= _PointNo; i++)
{
h[i] = (int)Math.Sqrt((_Points[i].X - _Points[DiemCuoi].X)
* (_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
Font(FontFamily.GenericSerif, 13, FontStyle.Bold, GraphicsUnit.Pixel, 8,
false), Brushes.Black, _Points[i].X - 10, _Points[i].Y - 23);
}
}
}


×