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

Đồ án thuật toán quay lui

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 (133.34 KB, 18 trang )

ĐẠI HỌC ĐÀ NẴNG
TRƯỜNG ĐẠI HỌC SƯ PHẠM

KHOA TIN HỌC

ĐỒ ÁN THUẬT TOÁN
ĐỀ TÀI

THUẬT TOÁN QUAY LUI
VÀ ỨNG DỤNG
ĐỂ TÌM ĐƯỜNG ĐI TRONG MÊ CUNG

Đà Nẵng – 2018


Mục lục


MỞ ĐẦU
1. Lí do chọn đề tài
Trong cuộc sống có nhiều vấn đề buộc ta phải lựa chọn hoặc tìm ra những
phương án để giải quyết được vấn đề. Trong toán học cũng thế, để giải một bài
toán đòi hỏi ta phải chọn được phương án giải quyết bài toán một cách tối ưu để
thu được kết quả mong muốn. Vấn đề đặt ra ở đây là, trong Tin học với mỗi bài
toán thường có rất nhiều phương pháp giải. Nhưng để tìm được phương pháp giải
tối ưu không phải là vấn đề đơn giản. Giả sử đặt vào bài toán tìm trường hợp tối ưu
trong các liệt kê tổ hợp luôn là một trong những bài toán được quan tâm hàng đầu
hiện nay. Một bài toán liệt kê tổ hợp cần được đảm bảo không được bỏ sót cũng
như trùng lặp bất kỳ một trường hợp nào. Phương pháp quay lui (backtracking) là
một trong những phương pháp liệt kê tổ hợp hữu hiệu và mang tính phổ dụng cao.
Tuy là thuật toán quay lui là không mới, không tối ưu trong việc giải quyết một số


bài toán, nhưng cũng có nhiều bài toán ứng dụng như hoán vị, tập con, tìm đường
đi hay mê cung thì cũng chỉ có thuật toán quay lui là lựa chọn phù hợp, nó giúp
giải quyết vấn đề một cách đơn giản và dễ dàng hơn. Vì vậy mà “thuật toán quay
lui và ứng dụng” được lựa chọn làm đề tài.
Ý tưởng cơ bản của “thuật toán quay lui” là liệt kê hết tất cả các khả năng có
thể, hay còn gọi là phương pháp vét cạn, duyệt hết cấu hình.
2. Mục tiêu và nhiệm vụ
- Nghiên cứu tổng quan về thuật toán quay lui. (lịch sử ra đời, cơ sở lý thuyết, khái
niệm, những ưu điểm, hạn chế của thuật toán)
- Ứng dụng của thuật toán quay lui vào các bài toán điển hình.
3. Cấu trúc báo cáo
Chương 1: Cơ sở lý thuyết về thuật toán quay lui
Chương 2: Phát biểu vấn đề


Chương 3: Kết quả và ứng dụng
CHƯƠNG 1: CƠ SỞ LÝ THUYẾT
1.1. Lịch sử ra đời
- “Backtrack” (quay lui) được giới thiệu lần đầu tiên bởi nhà toán học người Mỹ
Dr.D.H. Lehmer vào năm 1950.
- R.J Walker là người đầu tiên mô phỏng thuật toán này vào năm 1960.
- Sau đó, thuật toán quay lui được S. Golamb và L. Baumert phát triển.
1.2. Tổng quan về thuật toán quay lui
1.2.1. Khái niệm
- Quay lui (backtracking) là phương pháp thử các khả năng của bài toán cho đến
khi tìm thấy lời giải đúng. Phương pháp quay lui về bản chất là quá trình tìm kiếm
theo chiều sâu (Depth first search – DFS) trên đồ thị không gian trạng thái của bài
toán.
1.2.2. Dấu hiệu nhận biết bài toán có thể sử dụng thuật toán quay lui
- Một bài toán liệt kê tổ hợp luôn cần phải đảm bảo hai nguyên tắc, đó là: không

được bỏ sót một cấu hình và không được trùng lặp một cấu hình. Có thể nói rằng
phương pháp liệt kê là cách cuối cùng để có thể giải được một số bài toán tổ hợp
hiện nay. Một trong những phương pháp liệt kê có tính phổ dụng cap đó là thuật
toán quay lui.
- Một số bài toán liệt kê đơn giản:
 Liệt kê các tổ hợp của hoán vị
 Liệt kê các số tự nhiên chia hết cho 5
 Liệt kê các đường đi để thoát khỏi mê cung


1.2.3. Ý tưởng của thuật toán
Tại mỗi bước, nếu có lựa chọn được chấp nhận thì ghi nhận lại lựa chọn này
và tiến hành thử các bước thử tiếp theo. Còn ngược lại không có lữa chọn nào thích
hợp thì làm lại bước trước, xóa bỏ ghi nhận và quay về chu trình thử các lựa chọn
còn lại.
Hành động này được gọi là quay lui, thuật toán thể hiện phương pháp này gọi
là quay lui.
Điểm quan trọng của thuật toán là phải ghi nhỡ mỗi bước đi qua để tránh trùng
lặp khi quay lui. Dễ thấy là các thông tin này được lưu trữ vào một ngăn xếp, nên
thuật toán thể hiện ý thiết kế một cách đệ quy.
1.2.4. Các bước thiết kế thuật toán quay lui
Để xây dựng thuật toán quay lui, chúng ta cần phải phân tích bài toán để thiết kế
bốn bước cơ bản dưới đây:
1/ Chọn cách biểu diễn giải pháp
2/ Xây dựng các tập rẽ nhánh A1, A2…An và xếp thứ tự các phần tử của chúng sao
cho dễ xử lý.
3/ Xây dựng các điều kiện từ ràng buộc của bài toán để xác định một giải pháp
từng phần có là triển vọng không, được gọi là điều kiện tiếp tục.
4/ Chọn tiêu chí để xác định một giải pháp từng phần có là giải pháp cuối cùng
không.

1.2.5. Mô tả
Lời giải của bài toán thường biểu diễn một vec tơ gồm n phần tử A= (A 1…An).
Phải thỏa mãn các điều kiện nào đó. Để chỉ ra lời giải A, ta phải xây dựng dần các
thành phần lời giải Ai.
Tại bước i:
- Đã xây dựng xong các thành phần A1,….Ai-1


- Xây dựng thành phần Ai bằng cách lần lượt thử các khả năng mà Ai có thể chọn.
 Nếu một khả năng j nào đó phù hợp cho A i thì ta xác định Ai theo khả năng j.

Thường phải thêm các thao tác ghi nhận trạng thái của bài toán để hỗ trợ cho bước
quay lui. Nếu i=n thì ta có được một lời giải, ngược lại thì tiến hành bước i+1 để
xác định xi+1.
 Nếu không có một khả năng nào chấp nhận được cho xi thì ta lùi lại bước trước
(bước i-1) để xác định lại thành phần Ai-1.
Để đơn giản, ta giả định các khả năng lựa chọn cho các A i tại mỗi bước như
nhau, dó đó ta phải có thêm một thao tác kiểm tra khả năng j nào là chấp nhận cho
Ai .
Ta có thể trình bày quá trình tìm kiếm lời giải qua thuật toán quay lui bằng cây
sau:

Giải thuật tổng quát
Tìm nghiệm bằng thuật toán quay lui có thể chuyển về tìm kiếm trên cây khôn
gian trạng thái, với cây được xây dựng từng mức như sau:
- Các nút con của gốc (thuộc mức 1) là các khả năng có thể chọn cho x1.


- Giả sử Ai-1 là một nút ở mức thứ i-1, khi đó các nút con của A i-1 là các khả năng
mà Ai có thể chọn, một khi đã tìm được các thành phần A1…Ai-1.

Như vậy, mỗi nút A i của cây biểu diễn một lời giải bộ phận, đó là các nút nằm
trên đường đi từ gốc đến nút.
Ta có thể nói việc tìm kiếm nghiệm bằng thuật toán quay lui chính là tìm kiếm
theo chiều sâu trên cây không gian các trạng thái.
1.2.6. Cấu trúc chung của thuật toán quay lui
Input: Các tập hợp A1, A2, …., An
Output: Các tập con S của A1 x A2 x …. x An thỏa mãn ràng buộc của bài toán
Sử dụng đệ quy
algorithm Quaylui_Dequy (k)
begin
if ( S= ( s1, s2, …, sk-1 ) là giải pháp ) then xuly (s)
else
// Thử tất cả các giá trị có thể
for j  1 to |Ak| do
Sk  akj
// Ak = { ak1 , ak2 , ....}
if ( ( s1, s2, …, sk là có triển vọng ) then
Quaylui_Dequy (k+1) // Lựa chọn tiếp theo
endif
endof
endif
end
Sử dụng vòng lặp
algorithm Quaylui_Vonglap (k)


begin
k  1, ik  0
while ( k > 0 ) do
ik  ik + 1

v  false
while ( v = false and ik ≤ |Ak| ) do
sk = akik
if ( ( s1, …, sk ) là có triển vọng ) then
v  true
else

ik  ik+1

endif
endwhile //Thử giá trị tiếp theo
if ( v = true ) then
if ( S = ( s1, …., sk ) là giải pháp cuối cùng ) then xuly(s)
else
k  k+1
//Xây dựng thành phần tiếp theo
ik  0
endif
else k  K-1
endif
//Quay lui lại thành phần trước đó
endwhile
end



CHƯƠNG 2 : PHÁT BIỂU VẤN ĐỀ
2.1. Đề bài
- Giả sử một mê cung được định nghĩa là một lưới có n x n ô. Tìm đường đi trong
mê cung xuất phát từ ô (1,1) đến ô (n,n) sao cho mỗi ô chỉ qua đúng một lần. Biết

rằng, chỉ cho phép di chuyển lên, xuống, trái và phải nếu như vị trí tiếp theo là
trống và nằm trong mê cung.
2.2. Phân tích
Chúng ta có thể phân tích bài toán mê cung như sau:
- Dùng ma trận M [ 1..n, 1..n ] để lưu trữ mê cung sao cho: M [ i,j ] = 0 nếu ô (i,j)
là rỗng, và ngược lại M [ i,j ] = 1 nếu ô (i,j) có chướng ngại vật.
- Tìm tất cả các đường đi S = ( s1, s2, …., sn ), sk trong {1,…., n} x {1,…., n} chỉ ra
chỉ số tương ứng ô đi đến các bước k sao cho:






s1 là ô xuất phát ( 1, 1 )
sm là ô đích ( n,n )
M[sk] = 0 ( ô được đi đến phải rỗng )
si ≠ sj với mọi i ≠ j ( mỗi ô chỉ đi qua nhiều nhất một lần )
sk-1 và sk là các ô kề nhau

2.3. Thiết kế thuật toán
Từ những phân tích trên, chúng ta có các bước thiết kế cho thuật toán quay lui như
sau:
1/ Biểu diễn giải pháp: Giải pháp được biểu diễn bởi véc – tơ S = (s1, s2, …., sn) với
sk là ô đi đến ở bước k.
2/ Xây dựng tập đầu vào A1, A2, …., An và thứ tự các phần tử: Ak = {1, …, n} x {1,
…, n}, với mọi k, các phần tử sẽ được xử lý tăng dần.
3/ Điều kiện tiếp tục: Giải pháp từng phần S = (s1, s2, …, sn) phải thoản mãn ràng
buộc bài toán là:



 M[sk] = 0
 si ≠ sj với mọi i ≠ j
 sk-1 và sk là các ô kề nhau

4/ Tiêu chí để xác định một giải pháp từng phần có là giải pháp cuối cùng: sk là ô
đích ( n,n ).
Thuật toán quay lui tìm đường đi trong mê cung
Input: số ô n, ma trận mê cung M [ 1..n, 1..n ]
Output: in tất cả các cách đi
alogrithm MeCung (k)
begin
if ( s [k-1] = ( n,n ) ) then print ( s [1..k-1] )
else
//Đi lên
s [k] . i  s [k-1] . i-1, s [k] . j  s [k-1] . j
if (TrienVong ( s [1…k] ) ) then MeCung ( k+1 ) endif
// Đi xuống
s [k] . i  s [k-1] . i+1, s [k] . j  s [k-1] . j
if (TrienVong ( s [1…k] ) ) then MeCung ( k+1 ) endif
//Qua trái
s [k] . i  s [k-1] . i, s [k] . j  s [k-1] . j - 1
if (TrienVong ( s [1…k] ) ) then MeCung ( k+1 ) endif
// Qua phải
s [k] . i  s [k-1] . i-1, s [k] . j  s [k-1] . j + 1
if (TrienVong ( s [1…k] ) ) then MeCung ( k+1 ) endif
endif
end.
Hàm TrienVong



TrienVong ( s[1…k] )
begin
if ( s[k] . i < 1 or s[k] . I > n or s[k] . j < 1 or s[k] . j > n ) then
return false // Ô ngoài mê cung
endif
if ( M[ s [k] . i, s [k] . j ] = 1) then return false endif
for q from 1 to k-1 do
if ( s[k] . i = s [q] . i and s [k] . j = s [q] . j ) then
return false
endif
endof
return true
end


CHƯƠNG 3: KẾT QUẢ VÀ ỨNG DỤNG
[Nêu các ứng dụng, kết quả của thuật toán, chương trình....]
3.1
3.2

KẾT LUẬN
1. Kết luận
- Với vấn đề đặt ra “thuật toán quay lui và ứng dụng để tìm đường đi trong mê
cung”, đồ án đã đạt được một số kết quả:
 Tìm hiểu cơ sở lý thuyết của thuật toán quay lui
 Ứng dụng để tìm đường đi trong mê cung
 Cài đặt chương trình và chjay thử nghiệm-

Đồ án có thể được ứng dụng trong quá trình học tập của sinh viên.

2. Hướng nghiên cứu tiếp theo
- Tiếp tục tìm hiểu các bài toán có thể giải quyết được bằng thuật toán quay lui.
- Kết hợp thuật toán quay lui với một số kĩ thuật như nhánh cận nhằm đạt hiệu quả
tốt nhất.
- Xây dựng chương trình ứng dụng có giao diện trực quan, dễ sử dụng hơn.


TÀI LIỆU THAM KHẢO
1. />2. />%C3%A1y_t%C3%ADnh)
3. />4. a/p/thuat-toan-quay-lui-backtracking-bJzKmLbD59N
5. />6. />7. />

PHỤ LỤC
Chương trình minh họa 1.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define nmax 1000
FILE *fpin, *fpout;
int s_i[nmax], s_j[nmax];
int di[4]={-1, 0, 0, 1};
int dj[4]={0, -1, 1, 0};
int M[nmax][nmax];
int n;
void doc_du_lieu() {
int i,j,l;
/* doc du lieu vao tu tep tin input.txt */
if ((fpin = fopen("input.txt", "r")) == NULL) {
printf ("khong the mo tep du lieu vao! \n");
exit(1);

}
fscanf (fpin, "%d", &n);
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
fscanf (fpin, "%d", &M[i][j]);
fclose (fpin);


}
int trienvong (int k) {
int q;
if (s_i[k]<1 || s_i[k]>n || s_j[k]<1 || s_j[k]>n)
return 0;
if (M[s_i[k]][s_j[k]] == 1) return 0;
for (q=1; qif (s_i[k] == s_i[q] && s_j[k] == s_j[q])
return 0;
return 1;
}
void mecung(int k) {
int q;
if (s_i[k-1] == n && s_j[k-1] == n) {
for (q=1; qfprintf (fpout, "(%d %d)", s_i[q], s_j[q]);
fprintf (fpout, ".\n");
}
else
for (q=0; q<4; q++) {
s_i[k] = s_i[k-1] + di[q];
s_j[k] = s_j[k-1] + dj[q];

if (trienvong (k)) mecung(k+1);
}
}


int main() {
doc_du_lieu();
//mo file ghi ket qua output.txt
if ((fpout = fopen("output.txt", "w")) == NULL){
printf ("khOng the mo tep tin ghi ket qua. \n");
exit (1);
}
s_i[1] = s_j[1] =1;
mecung(2);
fclose (fpout);
return 0;
}
Giải thích chương trình
- Dữ liệu đầu vào được lưu trong tệp tin input.txt. Có cấu trúc như sau: dòng đầu
tiên chứa một số nguyên dương n; các dòng tiếp theo là ma trận n x n biểu diễn mê
cung (0 là rỗng, 1 là chướng ngại vật)
- Các cách đi được ghi trong tệp tin output.txt, mỗi cách đi thể hiện bằng một véctơ S = ( s1, s2, …., sn) được ghi trên một dòng.
- Lệnh FILE *fpin, *fpout dùng để gọi tập tin văn bản vào chương trình.
- Lệnh fscanf (fpin, "%d", &n) đọc dữ liệu từ file input.txt.
- Lệnh fprintf(fpout, "(%d %d)", s_i[q], s_j[q]) dùng để in vào file output.txt





×