Tải bản đầy đủ (.doc) (10 trang)

Báo cáo trí tuệ nhân tạo: Áp dụng thuật toán Hill-climbing để giải bài toán N- Queen

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 (146.54 KB, 10 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
Báo cáo bài tập lớn
Môn: Nhập môn trí tuệ nhân tạo
Đề bài: áp dụng thuật toán Hill-climbing để giải bài toán N- Queen.
Phần I: Giới thiệu về bài toán N – Queen:
a. Lịch sử:
Cơ sở của bài toán được đưa ra lần đầu tiên vào năm 1848 bởi Mazbezzel
với đề bài là xếp 8 quân hậu.Sau đó đã có rất nhiều nhà khoa học nghiên
cứu.Năm 1874 nauck tổng quát hóa bài toán thành bài toán xếp N quân.
Trong lập trình AI, bài toán xếp n-queen là một trong những bài toán cơ bản,
thường được dùng để đánh giá sức mạnh của một thuật toán.Ngoài ra bài
toán n-queen cũng được ứng dụng nhiều trong những lĩnh vực khác.
b. Đề bài:
Cho một bàn cờ kích thước n >=4.Đặt n quân hậu trên bàn cờ sao cho không
có quân nào có thể ăn được quân khác.Hay nói một cách khác, không quân
hậu nào có thể di chuyển theo quy tắc cờ vua. Mầu của các quân hậu là
không có ý nghĩa trong bài toán này. Như vậy lời giải của bài toán là 1 cách
xếp n quân hậu sao cho không có 2 quân nào đứng cùng 1 hàng, một cột,
hoặc 1 đường chéo.
c. Các lời giải cho bài toán:
Với n = 8.Bài toán có tất cả 92 lời giải.Trong đó, nếu loại đi các trường hợp
đối xứng thì bài toán chỉ còn 12 lời giải:
Một trong số những lời giải của bài toán 8 queen:
Cho đến nay vẫn chưa có công thức tính toán chính xác số lượng lời giải cho
bài toán tổng quát n-queen.
Phần II: Thuật toán Hill-climbing và các thuật toán khác để giải bài toán n-queen:


Có nhiều thuật toán để giải bài toán n – queen. Ở đây chỉ nêu và so sánh 4 thuật
toán cơ bản là: backtracking, hill-climbing, gene và thuật toán chia để trị
a. Thuật toán backtracking:
Ý tưởng của thuật toán duyệt bài toán theo chiều sâu, tức là: đặt từng quân
hậu lên bàn cờ sao cho con hậu đang đặt không được tấn công các con hậu
trước đó dã có trên bàn cờ.Nếu ở 1 tinh huống mà con hậu thứ k không thể
đặt lên bàn cờ (nói cách khác là tất cả các ô trên bàn cờ đều bị k-1 con hậu
trước đó tấn công) thì đặt lại con hậu thứ k-1 vào vị trí khác.
Giả mã:
Procedure Try_row(i)
For j=1 To n do
If not ok_row(i) And not ok_col(j) And not ok_plus(i+j-1) And not
ok_minus(i-j+n) then
{
solution(i)=j;
ok_col(j)=True;
ok_plus(i+1)=True;
ok_minus(i-j+n)=True;
If i<n then
try_row(i+1)
ELSE print_solution();
ok_row(i)=False;
ok_col(j)=False;
ok_plus(i+j-1)=False;
ok_minus(i-j+n)=False;
}
Nhận xét: Ưu điểm của thuật toán là dễ cài đặt, có thể đưa ra tất cả lời gải
của bài toán. Khuyết điểm của giải thuật là thời gian chạy lâu, tón nhiều tài nguyên
hệ thống.
b. Thuật toán hill-climbing:

Giải thuật leo đồi chính là nền tảng cơ sở của các kỹ thuật tìm kiếm cục bộ.
Mặc dù đây là giải thuật đơn giản nhưng lại nó lại rất mạnh và hiệu quả
trong việc giải quyết các bài toán CSP lớn. Thuật ngữ “leo đồi” (hill-
climbing) xuất phát từ cơ chế “tu chỉnh lập”: ở mỗi bước của việc tìm kiếm,
chúng ta sẽ chọn một bước chuyển mà nó cải thiện giá trị hàm mục tiêu để
thực hiện. Giải thuật leo đồi được mô tả như sau:
Procedure Hill_Climbing_Search;
Begin
Khởi tạo danh sách L chỉ chứa trạng thái đầu;
Loop do
If L rỗng 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; }
For mỗi trạng thái v kề u đặt v vào L sao cho các phần tử được
đưa vào đầu danh sách L có đánh giá giảm dần;
End;
Trong giải thuật leo đồi, chỉ những bước chuyển cải thiện được hàm chi phí
hoặc không làm cho hàm chi phí thay đổi mới được chọn vì vậy việc tìm
kiếm sẽ liên tục bước lên vị trí cao hơn cho đến khi nó gặp điều kiện dừng.
Khuyết điểm của giải thuật leo đồi:
Vấn đề lớn nhất mà giải thuật leo đồi mắc phải là nó sẽ bị rơi vào vùng tối
ưu cục bộ, đó là lúc chúng ta leo lên một đỉnh mà chúng ta không thể tìm
được láng giềng nào tốt hơn được nữa nhưng đỉnh này lại không phải là đỉnh
cao nhất.
Tối ưu cục bộ và tối ưu toàn cục
Khi leo đến một đỉnh tối ưu cục bộ, để tìm được lời giải tốt hơn nữa ta có thể
lặp lại thuật toán leo đồi với nhiều điểm xuất phát khác nhau được chọn
ngẫu nhiên và lưu lại kết quả tốt nhất ở mỗi lần lặp. Nếu số lần lặp đủ lớn thì
ta có thể tìm được đỉnh tối ưu toàn cục, tuy nhiên với những bài toán có
không gian tìm kiếm khổng lồ (chẳng hạn như bài toán xếp lịch) ta không

thể đưa ra số lần lặp đủ lớn để đảm bảo tìm được lời giải tối ưu. Cho nên đây
là phương pháp giải quyết không mang lại nhiều hiệu quả, chúng ta sẽ khảo
sát các giải thuật cải tiến khác khắc phục được vấn đề này ở phần sau.
Nhận xét: hiệu quả của giải thuật leo đồi phụ thuộc rất nhiều vào “bề mặt”
của không gian tìm kiếm bài toán. Nếu bài toán chỉ có vài đỉnh tối ưu cục bộ
thì giải thuật sẽ tìm ra lời giải tối ưu rất nhanh, tuy nhiên trong trường hợp
bề mặt không gian tìm kiếm lại quá lồi lõm (rất nhiều đỉnh tối ưu cục bộ),
giải thuật sẽ bị luẩn quẩn trong vùng tối ưu cục bộ và có thể không tìm ra
được lời giải tối ưu của bài toán.
Việc khắc phục và áp dụng thuật toán này để giải bài toán n-queen sẽ được
trình bày kĩ hơn trong phần III
c. Thuật toán gene:
Xếp N hậu lên các vị trí bất kì. Ứng với mỗi trạng thái của bàn cờ ta mã hóa
chúng thành các gen (hay các mảng 1 chiều).Cho các gen đó lai ghép với
nhau để tạo ra các gen mới.Kiểm tra trong số các gen con, xem có gen nào
là trạng thái kết thúc chưa(trạng thái chứa lời giải) nếu có thì dừng lại và đưa
ra lời giải, nếu chưa thì chọn lấy 1 số gene tốt ở cả trong các gene cha mẹ và
gene con để tạo ra thế hệ sau.Tiếp tục cho lai ghép đến khi tìm được trạng
thái kết thúc.
d. Thuật toán chia để trị
Ý tưởng thuật toán:
Chia bài toán xếp N hậu thành 1 số trường hợp.
Ví dụ về 1 cách chia trường hợp:
N từ 4->50 là 1 trường hợp, N từ 50->100 là 1 trường hợp
Tất nhiên đây chỉ là minh họa cho việc chia trường hợp. Thực tế thì không
thể chia như trên, bởi vì N ở đây có thể tiến tới vô cùng, ta phải có 1 cách
chia hợp lý, vửa đảm bảo vét hết tất cả các N, vừa đảm bảo có được lời giải
cho từng trường hợp một. Cụ thể như sau:
thực hiện qua 7 bước:
1. Chia n cho 12 lấy số dư r. (r= 8 với bài toán tám quân hậu).

2. Gán lần lượt các số chẵn từ 2 đến N vào N/2 phần tử đầu tiên của mảng
N phần tử đã tạo từ trước.
3. Nếu số dư r là 3 hoặc 9, chuyển 2 xuống cuối mảng.
4. Bổ sung lần lượt các số lẻ từ 1 đến n vào cuối mảng, nhưng nếu r là 8,
đổi chỗ từng cặp nghĩa là được 3, 1, 7, 5, 11, 9, ….
5. Nếu r = 2, đổi chỗ 1 và 3, sau đó chuyển 5 xuống cuối mảng.
6. Nếu r = 3 hoặc 9, chuyển 1 và 3 xuống cuối danh sách.
7. Lấy danh sách trên làm danh sách chỉ số cột, ghép vào danh sách chỉ số
dòng theo thứ tự tự nhiên ta được một lời giải của bài toán.
Nhậ xét: như ta thấy, bài toán tổng quát xếp N hậu được chia làm 4 trường
hợp, và ta đã có cách xếp hậu cho mỗi trường hợp đó:
- 1 là với r(số dư) = 0,1,4,5,6,7,8,10,11
- 2 là với r = 3,9
- 3 là với r = 2
- 4 là với r = 8
Phần III: Áp dụng Hill-climbing để giải bài toán xếp n - queen:
a. Cách lưu trữ dữ liệu (cấu trúc dữ liệu)
Thông thường chúng ta sẽ lưu bàn cờ dưới dạng mảng 2 chiều.Nhưng "trong
bài toán xếp N hậu" thì cách lưu trữ này tỏ ra thiếu hiệu quả và tốn dữ liệu.
Có một cách lưu trữ bàn cờ khác như sau:Tạo 1 mảng gồm N phần tử.Giá trị
của mỗi phần tử phải đôi một khác nhau và phải < N. Mỗi phần tử sẽ đại
diện cho 1 quân hậu. Trong đó chỉ số của phần tử trong mảng được coi là chỉ
số cột của con hậu tương ứng. Giá trị của mỗi phần tử ta coi như là chỉ số
hàng của con hậu tương ứng.Với cách lưu trữ này ta vừa có thể giảm số ô
cần lưu trữ vừa loại đi rất nhiều trường hợp xếp hậu sai vị trí.Cụ thể như sau
sau:
Giả sử ta có 1 cách xếp hậu chính xác (không con hậu nào ăn nhau) thì
chúng (tức là tất cả N con hậu) mỗi con phải nằm trên 1 hàng và 1 cột. Cách
lưu bàn cờ như đã giới thiệu đảm bảo rằng tất cả N con hậu, mỗi con đứng
trên 1 hàng và 1 cột riêng. Cụ thể: vì chỉ số của mỗi phần tử trong mảng

chạy từ 0->N-1 và luôn khác nhau.Mà như trên đã nói, mỗi phần tử đại diện
cho 1 con hậu, chỉ số của mỗi phần tử là chỉ số cột của mỗi con hậu > N
con hậu của chúng ta sẽ luôn có chỉ số cột chạy từ 0->N-1 và đôi 1 khác
nhau. Tương tự cho trường hợp chỉ số hàng tương ứng với giá trị của mỗi
phần tử trong mảng.Nhưng vì giá trị của mỗi phần tử trong mảng có thể thay
đổi và không chác đã khac nhau nên cần có 1 hàm kiểm tra để đảm bảo
những giá trị của các phần tử luôn < N và đôi 1 khác nhau.Cách lưu trữ dữ
liệu như đã nói còn tiện cho việc kiểm tra đường chéo.Vì như ta đã biết, N
con hậu không chỉ đứng trên các hàng, cột khác nhau, mà chúng còn đứng
trên các đường chéo khác nhau.Để biết được 2 con hậu có nằm trên 1 đường
chéo không ta sử dụng định lý sau:
+ các phần tử nằm trên cùng một đường chéo song song với đường chéo
chính có hiệu chỉ số hàng với chỉ số cột bằng nhau; (đường chéo chính là
đường chéo từ phía trên bên trái xuống phía dưới tay phải)
+ các phần tử nằm trên cùng một đường chéo song song với đường chéo phụ
có tổng chỉ số hàng với chỉ số cột bằng nhau;(đường chéo phụ là đường chéo
từ phía trên bên phải xuống phía dưới bên trái)
thuật toán kiểm tra đường chéo như sau:
int arr[N] //mảng N con hậu

for(int i = 0;i < N; i++)
{
for(int j = i + 1;j < N; j++)
{
iF((arr + i == arr[j] + j) || (arr - i == arr[j] - j))
{
con hậu thứ i và con hậu thứ j bị cùng nằm trên 1
đường chéo
}
}

}
b. Thuật toán hill-climbing khi áp dụng giải bài toán n – queen
Ý tưởng của thuật toán: Xếp tất cả N con Hậu lên bàn cờ (mỗi con hậu chếm
1 ô cờ). Mỗi một cách xếp như vậy được gọi là 1 State (trạng thái). Để lưu
trữ các trạng thái ta dùng cấu trúc dữ liệu như đã trình bày trên phần 1.Tức
là mỗi trạng thái sẽ được lưu thành 1 mảng N phần tử, chỉ số của mỗi phần
tử là chỉ số cột của mỗi con hậu, giá trị của mỗi phần tử là chỉ số hàng của
mỗi con hậu. và giá trị của mỗi phần tử trong mảng phải khác nhau và phải <
N. Để sinh ra các trạng thái con của một trạng thái A nào đó, ta hoán đổi giá
trị của phần tử thứ i và phần tử thứ j của mảng A. Để đánh giá 1 trạng thái
của bàn cờ, ta đếm xem có bao nhiêu "cặp hậu" nằm thẳngtrên cùng một
đường chéo.Bởi vì ta đã dùng cấu truc dữ liệu (như ở phần a đã nói), với cấu
trúc này ta không cần thiết kiểm tra các con hậu nằm trên 1 hàng hoặc 1 cột.
Hàm đánh giá của chúng ta sẽ trả về số cặp quân hậu ăn nhau trên các đường
chéo.
Giả mã:
//hàm hillclimbing
Tạo 1 biến currentState //để lưu trạng thái hiện tại
Tạo mảng successor //để lưu trạng thái kế tiếp, ban đầu successor chứa
trạng thái bắt đầu.
do
{
if (successor.Count == 0)
{
//thông báo thất bại
break;
}
currState = successor[0];
//loại trạng thái ở đầu danh sách
successor.RemoveAt(0);

//tạo trạng thái gần kề với trạng
getSuccessor(currState, successor);
//thai currentState và thêm vào mảng successor theo thứ tự giảm dần của
hàm đánh giá
} while (heuristics(currState)!= 0); //lặp cho đến khi gặp tráng thái kết thúc
xuất hiện.
Các hàm liên quan:
//Hàm đánh giá trạng thái: hàm đánh giá trạng thái trả về số lượng cặp quân hậu ăn
lẫn nhau
private int heuristics(State aState) //truyền vào 1 trạng thái
{
int n = 0;
for (i = 0; i < N - 1; i++)
{
for (j = i + 1; j < N; j++)
{
//Đếm số cặp quân hậu ăn nhau
if (aState.arrqueens[i] + i == aState.arrqueens[j] + j ||
aState.arrqueens[i] - i == aState.arrqueens[j] - j)
{
n++;
}
}
}
return n;
}
//Hàm tạo trạng thái getSuccessor, tạo ra trạng thái con của trạng thái aState và
thêm nó vào successor theo thú tự giảm dần của hàm đánh giá.
private void getSuccessor(State aState, State[] successor)
{

State childState; // trạng thái con
int p; // biến tạm
for (int i = 0; i < N; i++)
{
for (int j = i + 1; j < N; j++)
{
// tạo 1 trạng thái con mới
childState = new State(aState.arrqueens);
childState.h = heuristics(childState);
if (heuristics(childState) < heuristics(aState.h))
{
//chèn trạng thái con vào vị trí của nó
for (p = 0; p < successor.Count; p++)
{
if (heuristics(childState) < heuristics(successor[p]))
{
break;
}
}
successor.Insert(p, childState); //câu lệnh chèn
}
}
}
}
HẾT.
Bài viết là của sinh viên vũ minh đức; lớp tin hoc 5a trường HVKTQS. Bài viết đã
được tác giả đăng trên 1 số website.
Tài liệu tham khảo: winkipedia và 1 số tài liệu khác.

×