III. VẤN ĐỀ NGHIÊN CỨU KHOA HỌC CỦA CÁ NHÂN
3. Khái quát về các thuật toán, thuật giải, cấu trúc dữ liệu
3.2. Phƣơng pháp thử sai
a) Vét c ạn/duyệt toàn bộ
Vét cạn toàn bộ là một phƣơng pháp đƣợc sử dụng cho những bài toán có không gian tìm kiếm nhỏ. Chúng ta hãy xét một ví dụ sau:
Cho 100 con Trâu ăn 100 bó cỏ. Trâu đứng ăn 5, Trâu nằm ăn 3, Trâu già 3 con một bó. Tìm số Trâu mỗi loại.
Đây là một bài toán đố vui, việc của chúng ta là đi tinh số lƣợng của mỗi loại Trâu: Trâu đứng, Trâu nằm và Trâu già. Bài toán đƣợc mô phỏng dƣới cách nhìn của toán học, với không gian tìm kiếm định rõ:
i+j+k = 100 (1)
5i+3j+k/3 = 100 (2) Với: 0<= i <= 20 (*)
0<= j <=33 (**)
0<= k <= 100 && k mod 3 = 0 (***)
Bài toán đã đƣợc mô hình dƣới dạng hệ phƣơng trình bậc nhất 3 ẩn số, với miền tìm kiếm đƣợc giới hạn.
Để giải quyết bài toán này trên máy tính chúng ta sử dụng thuật toán vét cạn toàn bộ nhƣ sau:
B1: 0<= i <= 20 làm công việc sau: Timduocnghiem = false;
B1.1: 0<= j<= 33 làm công vi ệc sau:
B1.1.1 0<=k <= 100 và k chia hết cho 3 làm công việc sau: Kiểm tra biểu thức : i+j+k = 100 (1) 5i+3j+k/3 = 100 (2)
Trường Đại Học Công Nghệ Thông Tin – Sinh Viên: Ng uyễn Lâm Tú 06520525
Nếu biểu thức đúng thì gán Timduocnghiem = true.Thoái khỏi vòng lặp3
Ngược lại tiếp tục lặp
Kiểm tra Timduocnghiem = true thì thoat khỏi vòng lặp 2 Ngƣợc lại tiếp tục lặp
Kiểm tra Timduocnghiem = true . In ra nghiệm và thoát khỏi vòng lặp 1 Ngƣợc lại tiếp tục lặp
Hàm cài đặt:
Nguyên lý vét cạn đƣợc mô hình hóa dƣới dạng toán học nhƣ sau:
Gọi D(Domain) là không gian của vấn đề - bài toán (hay tập tất cả trƣờng hợp, khả năng có thể xảy ra của bài toán)
D = tập hợp tất cả các bộ (x1,x2,x3,…,xn) Trong đó: x1 thuộc D1 x2 thuộc D2 … xn thuộc Dn Và Di là các tập hợp hữu hạn có số phần tử là mi. Gọi quy tắc xác định lời giải là một ánh xạ f: f: D {True,False}
Trường Đại Học Công Nghệ Thông Tin – Sinh Viên: Ng uyễn Lâm Tú 06520525
Để tìm kiếm lời giải của bài toán, ta liệt kê (theo một thứ tự nào đó) và lần lƣợt xét tất cả các phần tử của tập D, nếu phần tử X = (x1,x2,..,xn) thỏa f(X) = True thì X là một lời giải của bài toán.
Rõ ràng phƣơng pháp vét cạn là một phƣơng pháp “thuần túy”, và khá “thông thƣờng”.Có thể hiểu đơn giản là muốn tìm đƣợc lời giải ta sét từng trƣờng hợp xảy ra cho tới khi tìm đƣợc lời giải hoặc hết trƣờng hợp. Làm nhƣ thế rõ ràng là khả chắc chắn, nếu có lời giải nhất định ta sẽ tìm ra. Điều này đã lợi dụng đƣợc sức
mạnh tính toán của máy tính. Tuy nhiên, đối với không gian tìm kiếm quá lớn thì
phƣơng pháp này khó có thể áp dụng.
Chúng ta sẽ xem xét một vài ví dụ có thể áp dụng đƣợc thuật toán này:
Ví dụ 1: Tìm một số có 3 chữ số sao nó bẳng tổng lập phƣơng của từng chữ số. Ví dụ 2: Có tờ 1 đồng, 2 đồng, 5 đồng. Hỏi cần bao nhiêu tờ 1 đồng, 2 đồng, 5 đồng để có 200 đồng.
b)Nguyên lý mắt lƣới
Chúng ta thấy đƣợc nhƣợc điểm của vét c ạn toàn bộ đó là không gian tìm kiếm. Để giảm bớt yếu điểm này ngƣời ta đƣa ra một nguyên lý: mắt lƣới.
Dựa vào đặc điểm của vấn đề mà ta có thể loại bớt một số trƣờng hợp và do đó loại bớt không gian tìm kiếm. Trở lại ví dụ phía trên phần vét cạn. Ta thấy đƣợc khác với i và j, k đƣợc tăng 3 đơn vị mỗi vòng lặp, nhƣ vậy đã giảm bớt đƣợc khá nhiều trƣờng hợp không c ần thiết.
Chúng ta hãy xét một bài toán c ụ thể sau:
Cho hàm số y = f(x) liên tục trong đoạn [a,b]. Giải phƣơng trình f(x) = 0 trong đoạn [a,b] với độ chính xác /x-x0/<epsilon. Với x0 là một trong các nghiệm của bài toán.
Vấn đề bài toán đặt ra là tìm đƣợc nghiệm của bài toán thỏa mãn độ chính xác epsilon. Chắc chắn một điểu rằng, nghiệm cần tìm nằm trong đoạn [a,b]. Thông thƣờng theo nguyên lý vét cạn ta sẽ tìm mọi điểm trên đoạn này và thử xem cái nào làm cho f(x) = 0. Rõ ràng việc xét đƣợc tất cả các giá trị của x trên đoạn này là điều không thể trong trƣờng hợp x là kiểu số hữu tỉ hay số thực. Số lƣợng x là qua lớn. Để giải quyết vấn đề này và để hạn chế không gín tìm kiếm ngƣời ta sử dụng nguyên lý mắt lƣới. Do độ chính xác là epsilon nên ta sẽ chia nhỏ đoạn [a,b] thành n đoạn có độ dài epsilon. Ta tìm đoạn có hai đầu lần lƣợt là x1,x2 thỏa:
f(x1)*f(x2)<0
nhƣ thế sẽ tồn tại nghiệm x0 thỏa : f(x0) = 0 trong đoạn [a,b] và có độ chính xác epsilon.
Thuật toán: B2: Gán x1 = a
Trường Đại Học Công Nghệ Thông Tin – Sinh Viên: Ng uyễn Lâm Tú 06520525 B4 : xác định nghiệm x0 = (x1+x1+n)/2 code: c) Mê cung
Nguyên lý mê cung là gì? Đối với vét cạn toàn bộ ta luôn có đƣợc miền vét cạn Domain cho trƣớc. Trong một bài toán nào đó khi mà Domain không đƣợc cho trƣớc thì làm cách nào có thể tìm ra lời giải.
Về bản chất, tƣ tƣởng của phƣơng pháp là thử từng khả năng cho đến khi tìm thấy lời giải đúng. Đó là một quá trình tìm kiếm theo độ sâu trong một tập hợp các lời giải. Trong quá trình tìm kiếm, nếu ta gặp một hƣớng lựa chọn không thỏa mãn, ta quay lui về điểm lựa chọn nơi có các hƣớng khác và thử hƣớng lựa chọn tiếp theo. Khi đã thử hết các lựa chọn xuất phát từ điểm lựa chọn đó, ta quay lại điểm lựa chọn trƣớc đó và thử hƣớng lựa chọn tiếp theo tại đó. Quá trình tìm kiếm thất bại khi không còn điểm lựa chọn nào nữa.
Quy trình đó thƣờng đƣợc cài đặt bằng một hàm đệ quy mà trong đó mỗi thể hiện của hàm lấy thêm một biến và lần lƣợt gán tất cả các giá trị có thể cho biến đó, với mỗi lần gán trị lại gọi chuỗi đệ quy tiếp theo để thử các biến tiếp theo. Chiến lƣợc quay lui tƣơng tự với tìm kiếm theo độ sâu nhƣng sử dụng ít không gian bộ nhớ hơn, nó chỉ lƣu giữ trạng thái của một lời giải hiện tại và cập nhật nó.
Để tăng tốc quá trình tìm kiếm, khi một giá trị đƣợc chọn, trƣớc khi thực hiện lời gọi đệ quy, thuật toán thƣờng xóa bỏ giá trị đó khỏi miền xác định của các biến có mâu thuẫn chƣa đƣợc gán (kiểm tra tiến - forward checking) và kiểm tra tất cả các hằng số để tìm các giá trị khác đã bị loại trừ bởi giá trị vừa đƣợc gán (lan truyền ràng buộc - constraint propagation).
Trường Đại Học Công Nghệ Thông Tin – Sinh Viên: Ng uyễn Lâm Tú 06520525
Theo nguyên lý Mê Cung ta phải xây dựng dần các thành phần của lời giải bằng cách thử lần lƣợt tất cả các khả năng có thể có. Nếu tồn tại một khả năng chấp nhận đƣợc thì xây dựng thành phần kế tiếp, ngƣợc lại, ta phải lùi lại thành phần trƣớc để thử các khả năng chƣa đƣợc thử qua. Chúng ta hãy xét bài toán sau:
Bài toán đặt ra ở đây đó là tìm cách nào để có thể đi từ ô màu xanh qua ô màu đỏ??
- Ta phải xét đƣờng đi cho tất cả các đỉnh mà ta đến. Việc chuyển đỉnh mới khi
có lối đi tiếp theo
- Tại mỗi đỉnh xét tất cả các khả năng cho đến khi tìm đƣợc trạng thái mới. Việc xét sẽ kết thúc khi tìm đƣợc trạng thái mới
- Với mỗi vị trí đi qua , cần đƣợc đánh dấu là đã đi qua rồi.
- Quay lui đƣợc thực hiện bởi đệ quy (stack)
- Có một số trạng thái của thuật giải đƣợc lƣu: lƣu các nút đã đi qua. Lƣu các bƣớc đi qua ma hiện tại cho là đúng. Biến lƣu 1 trạng thái hiện tại và biến lƣu các trạng thái có thể đi tiếp theo.
Giải thuật sau đƣợc đƣa ra: (chú ý rằng đây là thuật giải không phải thuật toán)
procedure Try(i: Integer); begin
for (mọi giá trị có thể gán cho xi) do
if(<chấp nhận đƣợc khả năng xi mới>)
Trường Đại Học Công Nghệ Thông Tin – Sinh Viên: Ng uyễn Lâm Tú 06520525
< cho xi := V>;
if (xi là phần tử cuối cùng trong c ấu hình) then <Thông báo c ấu hình tìm đƣợc>
else
begin
<Ghi nhận việc cho xi nhận giá trị V (Nếu cần)>; Try(i + 1); {Gọi đệ qui để chọn tiếp xi + 1}
<Nếu cần, bỏ ghi nhận việc thử xi := V, để thử giá trị khác>; end;
end; end;
(Thuật toán quay lui sẽ bắt đầu bằng lời gọi Try(1);)