Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 29 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
29
Dung lượng
399 KB
Nội dung
PHẦN I: PHẦN MỞ ĐẦU
I. Lý do chọn đề tài:
Ngôn ngữ lập trình là một trong những nội dung được đưa vào dạy chính thức
ở bộ môn Tin học ở nhà trường phổ thông. Như ta đã biết, các câu lệnh để giải
quyết bài toán Tin học được mô tả dưới các dạng tuần tự, rẽ nhánh và lặp.
Trong đó với các phép lặp, ta giải bài toán bằng cách thực hiện liên tiếp một số
các câu lệnh trong vòng lặp cho tới khi một điều kiện nào đó được thỏa mãn.
Một kỹ thuật lập trình được sử dụng để thay thế cho các phép lặp đó là kỹ
thuật đệ quy quay lui (Back tracking). Mặt khác, trong thực tế có rất nhiều bài
toán đòi hỏi sự lặp đi lặp lại một cách phức tạp. Và đệ quy quay lui cung cấp
cho ta cơ chế giải quyết bài toán phức tạp một cách đơn giản và dễ hiểu.
Đệ quy quay lui là một trong những chiến lược để giải quyết nhiều bài toán,
đặc biệt là các bài toán đòi hỏi liệt kê mọi cấu hình thoả mãn. Đặc biệt trong đề
thi học sinh giỏi Tỉnh các năm đệ quy quay lui luôn chiếm một phần quan trọng.
Đã có nhiều bài viết đề cập đến đệ quy quay lui và các vần đề xung quanh đệ quy
quay lui nhưng trong tài liệu này, tôi muốn đề cập tới “Đệ quy quay lui trên
mảng hai chiều” để làm đề tài sáng kiến kinh nghiệm của mình.
II. Mục đích nghiên cứu:
Đề tài: “Đệ quy quay lui trên mảng hai chiều” nhằm đạt mục đích sau:
−
Giúp cho bản thân có thể hiểu rõ hơn, sâu hơn về kỹ thuật đệ quy
quay lui, ứng dụng đệ quy quay lui để giải các bài toán trong Tin học, từ đó nâng
cao khả năng tự học, khả năng lập trình của bản thân.
− Nâng cao chất lượng bồi dưỡng học sinh giỏi môn Tin các kỳ thi.
− Góp phần làm đa dạng tài liệu nghiên cứu của tổ bộ môn.
III. Phương pháp nghiên cứu:
Khi nghiên cứu đề tài này tôi sử dụng các phương pháp sau:
−
Phương pháp nghiên cứu lý thuyết.
1
−
Sử dụng phương pháp thu thập thông tin và tổng hợp, phân tích, so
sánh dựa trên lý thuyết về đệ quy quay lui.
−
Áp dụng giải với một số bài toán cụ thể.
IV. Đối tượng nghiên cứu:
Đối tượng nghiên cứu của đề tài này đó chính là đệ quy quay lui và ứng
dụng của quay lui để giải các bài toán trong Tin học có liên quan tới mảng hai
chiều và các tài liệu, các thông tin liên quan.
Nội dung nghiên cứu được trình bày theo cấu trúc sau:
1. Nhắc lại kiến thức về đệ quy quay lui (Back tracking)
2. Bài toán kinh điển: Mã đi tuần
3. Ứng dụng quay lui để giải một số bài toán xử lý trên mảng hai chiều
Kết luận
2
PHẦN II: PHẦN NỘI DUNG
1. Nhắc lại kiến thức về đệ quy quay lui (Back tracking)
1.1. Tổng quan về đệ quy quay
lui
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ó.
Yếu tố mấu chốt trong một thủ tục đệ quy là điều kiện duyệt và điểm dừng. Với
đặc trưng của mảng hai chiều là phần tử mảng được xác định bằng hai giá trị hàng
và cột, thông thường chúng ta vẫn sử dụng cặp giá trị (i,j) (hàng, cột của 1 ô) làm
bước duyệt khi gọi thủ tục đệ quy.
1.2. Giải thuật tổng quát
Procedure Try(i); {Chọn thực hiện bước thứ i}
Begin
For CÁC PHƯƠNG ÁN CHỌN do
If CHỌN ĐƯỢC then
Begin
- THỰC HIỆN BƯỚC ĐI THỨ i;
- IF THÀNH CÔNG then THÔNG BÁO KẾT QUẢ
Else Try(i+1);
-HỦY BƯỚC ĐI THỨ i; {Quay lui}
End;
3
End;
- Thủ tục trên sẽ được khởi động bởi lệnh: Try(1);
2. Bài toán kinh điển: Mã đi tuần
2.1. Đề bài:
Mã đi tuần (hành trình của quân mã) là bài toán về việc di chuyển một
quân mã trên bàn cờ vua (8 x 8). Quân mã được đặt ở một ô trên một bàn cờ trống
nó phải di chuyển theo quy tắc của cờ vua để đi qua mỗi ô trên bàn cờ đúng
một lần. Hãy viết chương trình đặt quân mã vào một vị trí bất kỳ trên bàn cờ.
Tìm chu trình của quân mã để ghé thăm một lần duy nhất tất cả các ô còn lại
- Quy tắc di chuyển của quân mã trên bàn cờ vua: quân mã đi theo hình chữ
L
2.2. Phân tích bài toán:
Có rất nhiều lời giải cho bài toán này, chính xác là 26.534.728.821.064 lời giải
trong đó quân mã có thể kết thúc tại chính ô mà nó khởi đầu. Một hành trình như
vật được gọi là hành trình đóng.
Có những hành trình, trong đó quân mã sau khi đi hết tất cả 64 ô của bàn cờ
(kể cả ô xuất phát), thì từ ô cuối của hành trình không thể đi về ô xuất phát chỉ
bằng một nước đi. Những hành trình như vậy được gọi là hành trình mở.
Đối với bài toán mã đi tuần ta nhận thấy rằng, ban đầu tọa độ của quân mã là
(i,j) bất kỳ trên bàn cờ. Tại vị trí này theo quy luật di chuyển của quân mã trên bàn
cờ thì quân mã có tối đa 8 hướng đi tiếp theo. Rõ ràng để đi đến các lời giải ta
phải thử tất cả các trường hợp quân mã có thể đi đến ở bước 1. Với mỗi vị trí thử
như vậy ta lại thử tất cả các các trường hợp của quân mã có thể đi đến ở bước 2,…
4
Cứ tiếp tục như vậy cho đến khi quân mã đi qua tất cả các ô trên bàn cờ vua thì
dừng lại. Như vậy, tính chất đệ quy của bài toán đó thể hiện trong các phép thử
hướng đi của quân mã ở trên.
Kết quả ta tìm được nhiều chu trình đi khác nhau nhưng số bước đi đều là 63.
Sử dụng giải thuật đệ quy quay lui cho bài toán mã đi tuần, ta có:
- Try(k,i,j): Chọn thực hiện bước đi thứ k, với ô xuất phát là (i,j);
- Các phương án chọn: Có 8 phương án (tương ứng với 8 trường hợp có
thể đi đến của quân mã):
+ Kí hiệu phương án: m = 1, 2, …, 8.
+ Thiết lập hai mảng một chiều d,c lưu trữ tọa độ tương ứng 8 khả
năng di chuyển của quân mã:
d
-1
1
2
2
1
-1
-2
-2
Chỉ số m
1
2
3
4
5
6
7
8
c
-2
-2
-1
1
2
2
1
-1
Chỉ số m
1
2
3
4
5
6
7
8
Khi đó: phương án m là di chuyển mã đến ô (i+d[m], j+c[m]).
- Chọn được: nếu như ô (i+d[m], j+c[m]) quân mã chưa đi qua và 14->3
1->4->3
b, Phân tích: Tương tự bài 3.1 nhưng có 3 điểm cần bổ sung:
- Để tìm hết tất cả các đường đi thì cần trả lại trạng thái cho điểm vừa kết nạp để
tiến tới việc xét các điểm khác nhằm tìm ra con đường đi mới.
- Cần có một biến ktra lưu kết quả có đường đi hay không phục vụ cho việc in ấn
kết quả. (Vì mỗi lần ta lại trả lại trạng thái cho điểm mới kết nạp nên cx[Q] cuối
cũng vẫn là True)
- Trong thủ tục in kết quả cần sử dụng thủ tục append để ghi dữ liệu.
c, Chương trình:
PROGRAM LIET_KE_DUONG_DI_GIUA_2_DINH_P_Q;
const fi='DUONG.INP'; fo='DUONG.OUT';
var x:array[1..100] of integer;
a:array[1..100,1..100] of integer;
N,K,I,j,p,q,dem:INTEGER;
Cx:array[1..100] of BOOLEAN;
f:text;Ktra:boolean;
{---------Thu tuc doc du lieu---------}
procedure doc;
var i,j:integer;
begin
assign(f,fi);reset(f);
readln(f,n);
for i:=1 to n do
begin for j:=1 to n do read(f,a[i,j]);
readln(f);
end;
read(f,p,q);
14
close(f);
end;
{---------Thu tuc in ket qua---------}
procedure inkq;
var i:integer;f:text;
begin
Assign(f,fo); Append(f);
write(F,'Co duong di:');
for i:=1 to dem-1 do
write(f,x[i], '->');
Writeln(f,X[dem]);
close(f);
end;
{---------Thu tuc try---------}
procedure try(d,c:integer);
var j:integer;
begin
for j:=1 to n do
if (a[d,j]=1) and (cx[j]) then
begin
cx[j]:=false;
dem:=dem+1;
x[dem]:=j;
if j=Q then begin ktra:=true;
inkq ; end
else try(j,c);
dem:=dem-1;
cx[j]:=true;
end;
end;
BEGIN
doc;
{Khoi tao}
FOR I:=1 TO N DO Cx[I]:=TRUE;
dem:=1; cx[P]:=false;x[dem]:=P;
ktra:=false; {ban dau cho rang khong co duong di}
Try(P,Q);
if ktra=false then
begin assign(f,fo);rewrite(f);
15
write(f,'Khong co duong di');close(f);
end;
END.
3.2. Ứng dụng quay lui để giải một số bài toán xử lý trên mảng hai chiều kích
thước MxN.
3.2.1. Đếm số miền liên thông, miền liên thông lớn nhất.
a, Đề bài: Cho ma trận A cấp MxN, trên mỗi ô A[i,j] của lưới ghi số 0 hoặc 1.
Hai ô được gọi là liên thông trực tiếp nếu nó chung cạnh và cùng giá trị 1, ngược lại
có giá trị 0. Hãy cho biết lưới ô vuông có bao nhiêu miền liên thông và miền liên
thông nào là lớn nhất (có nhiều ô có giá trị 1 nhất) cùng với chỉ số của các ô đó.
Dữ liệu vào: Tệp văn bản DTLT.INP có dạng:
- Dòng đầu tiên gồm 2 số M, N.
- M dòng tiếp theo mỗi dòng ghi N số 0 hoặc 1
Dữ liệu ra: Tệp văn bản DTLN.OUT có dạng:
- Dòng đầu tiên ghi số liên thông.
- Dòng tiếp theo ghi dòng thông báo diện tích vùng liên thông lớn nhất
- Các dòng tiếp theo ghi các vị trí của các ô thuộc vùng liên thông lớn nhất.
Mỗi số phân cách nhau ít nhất một ký tự trống
Ví dụ:
Tệp DTLT.INP
44
1100
0110
0011
1100
Tệp DTLT.OUT
So lien thong:2
Vung lien thong dien tich lon nhat=6
Tai cac vi tri:
11
12
22
23
33
34
b, Phân tích
Ta thấy rằng mỗi một ô tại vị trí [i,j] có thể liên thông với 4 ô xung quanh (Trên,
dưới, phải, trái) của nó. Vì thế sử dụng 2 hằng mảng một chiều thể hiện độ biến
thiên của hàng, cột:
16
dx:array[1..4] of integer=(-1,1,0,0);
dy:array[1..4] of integer=(0,0,1,-1);
{Trên,dưới,phải,trái}
Ta sẽ xét tất cả các ô có trong lưới MxN nếu có giá trị là 1 và chưa được xét thì
ghi nhận có một miền liên thông. Để xác định ô đã được xét hay chưa ta dùng một
mảng hai chiều b. Ban đầu cho b toàn số 0. Sau khi thực hiện việc kiểm tra tại ô
a[i,j] nào đó, nếu nó thuộc miền liên thông nào thì sẽ xác định lại giá trị ô b[i,j] bằng
chính chỉ số miền liên thông vừa tìm được, đồng thời tăng diện tích miền liên thông
(biến dem) lên 1 đơn vị.
Với mỗi miền liên thông ta so sánh với giá trị max, nếu số ô trong miền liên thông
vừa tìm lớn hơn max thì ta gán giá trị của biến dem cho max, chỉ số miền liên thông
lớn nhất csmax chính bằng solt. Từ ô này ta xét các ô khác xung quanh chưa được
xét và có giá trị bằng 1 để kết nạp ô đó vào miền liên thông vừa xác định được. Lặp
lại việc này cho tới khi hết các ô trong luới.
Lưu ý:
- Ta phải làm công việc bao quanh lưới MxN một loạt các số 0 để các ô ở biên
của lưới cũng xét tương tự như các ô khác.
- Để biết được ô [i,j] nào đó thuộc miền liên thông nào ta căn cứ vào mảng b để
xác định được miền liên thông nào là lớn nhất cùng vị trí các ô trong miền.
c, Chương trình
program VUNG_LIEN_THONG_LON_NHAT;
uses crt;
const fi='DTLT.INP';fo='DTLT.OUT';maxM=50;
dx:array[1..4] of integer=(-1,1,0,0);
dy:array[1..4] of integer=(0,0,1,-1);
{Len,xuong,phai,trai}
VAR a,b:array[0..maxM+1,0..maxM+1] of byte;
solt,m,n,k,h,dem,csMAX,max:integer;
f:text;
{---------Thu tuc doc du lieu---------}
PROCEDURE DOCTEP;
var i,j:integer;
17
begin
assign(f,fi);reset(f); readln(f,m,n);
fillchar(a,sizeof(a),0); {Tao mang a toan so 0}
for i:=1 to m do
begin
for j:=1 to n do read(f,a[i,j]);
readln(f);
end;
close(f);
end;
{---------Thu tuc try---------}
PROCEDURE Try(r,c:integer);
var i:integer;
begin
for i:=1 to 4 do
{xet 4 vi tri xung quanh diem (r,c)}
if (a[r+dx[i],c+dy[i]]=1) and (b[r+dx[i],c+dy[i]]=0) then
begin
dem:=dem+1;
b[r+dx[i],c+dy[i]]:=solt;
try(r+dx[i],c+dy[i]);
end;
end;
{---------Thu tuc xu ly---------}
PROCEDURE XULY;
var h,k:integer;
begin solt:=0;
for k:=1 to m do
for h:=1 to n do
begin
if (a[k,h]=1) and (b[k,h]=0) then
begin
solt:=solt+1;
b[k,h]:=solt;
dem:=1;
try(k,h);
IF dem>MAX THEN begin max:=dem;csMAX:=solt;end;
end;
end;
18
end;
{---------Thu tuc in ket qua---------}
PROCEDURE INKQ;
var i,j:integer;
Begin
assign(f,fo);rewrite(f);
writeln(F,'So lien thong:',solt);
writeln(F,'Vung lien thong co dien tich lon nhat=',max);
writeln(F,'Tai cac vi tri:');
FOR I:=1 TO M DO
FOR J:=1 TO N DO
IF B[I,J]=csMAX THEN WRITELN(F,I,' ',J);
close(f);
end;
BEGIN
clrscr;DOCTEP;
fillchar(b,sizeof(b),0); max:=0;
XULY;
INKQ;
END.
3.2.2. Bài toán tần số phát sóng: (Bài 3 - Đề thi chọn HSG Tin 12 năm học
2013 – 2014)
Người ta phân hoạch một vùng đất hình chữ nhật thành MxN ô vuông bởi các
đường kẻ song song với các đường biên của vùng đất đó. Vị trí của mỗi mảnh đất ô
vuông được xác định bởi cặp số (x, y) trong đó x là số thứ tự dòng tính từ trên xuống
dưới, y là thứ tự cột tính từ trái sang phải của mảnh đất ô vuông đó khi ta nhìn từ
một mặt phẳng song song phía trên mặt phẳng vùng đất. Tại mỗi ô vuông của vùng
đất được đặt một máy phát sóng vô tuyến điện tử. Mỗi ngày có thể phát ra các loại
sóng có dải tần A hoặc B; tại mỗi thời điểm phát sóng chỉ phát ra mỗi loại sóng có
một dải tần số nào đó mà thôi. Ta có thể di chuyển từ vị trí máy phát sóng này đến vị
trí máy phát sóng khác nếu hai máy phát sóng đó nằm trên hai mảnh đất ô vuông có
cạnh chung. Một vùng máy phát sóng là tập hợp các mảnh đất ô vuông có trên đó
đặt các máy phát sóng phát ra loại sóng có cùng dãy tần số. Việc xác định hai máy
19
phát sóng nào đó nằm trên hai mảnh đất ô vuông có cùng một vùng phát sóng tại
một thời điểm phát sóng nào đó hay không có ý nghĩa cho việc lên kế hoạch phát
sóng trong lần phát sóng kế tiếp.
Cho trước vị trí của hai mảnh đất ô vuông, hãy xác định hai mảnh đất đó có cùng
một vùng phát sóng tại một thời điểm phát sóng nào đó hay không?
Dữ liệu vào là tệp văn bản TSPS.INP có cấu trúc:
− Dòng đầu tiên ghi 2 số M, N (1≤M≤100, 1≤N≤100)
− M dòng tiếp theo, mỗi dòng ghi N ký tự ‘A’ hoặc ‘B’ nếu máy phát sóng đặt
trên mảnh đất ô vuông tương ứng phát sóng loại sóng có dải tần số A hoặc B
trong một lần phát sóng.
− Các dòng tiếp theo, mỗi dòng ghi 4 số mô tả vị trí của hai mảnh đất ô vuông
mà ta cần kiểm tra chúng có cùng một vùng phát sóng hoặc không. 2 số đầu
ghi thứ tự dòng và số thứ tự cột của mảnh đất ô vuông thứ nhất, 2 số sau là
thứ tự dòng và số thứ tự cột của mảnh đất ô vuông thứ hai.
− Các ký tự trên cùng một dòng được ghi liên tiếp nhau. Các số trên cùng một
dòng được ghi cách nhau ít nhất một ký tự trống.
Dữ liệu ra là tệp TSPS.OUT có số dòng là số cặp mảnh đất ô vuông mà ta cần
kiểm tra xem chúng có cùng một vùng phát sóng hay không? Mỗi dòng ghi một số
là số 1 hoặc là số 0 nếu cặp mảnh đất ô vuông tương ứng có cùng một vùng phát
sóng hay không.
Ví dụ:
Tệp TSPS.INP
46
AABBAA
BAABAA
BBAABB
AABBBB
1234
2316
Tệp TSPS.OUT
1
0
b, Phân tích
20
Bài toán này giải quyết hoàn toàn tương tự như bài 3.1.2 – Kiểm tra tính liên
thông giữa nhiều cặp đỉnh của đồ thị. Ở đây chỉ khác là ma trận kích thước MxN nên
thủ tục Try phải bổ sung các tham số là chỉ số dòng và cột của hai điểm.
c, Chương trình
program Bai_3_HSG12_2013_2014;
uses crt;
const fi='TSPS.INP';fo='TSPS.OUT';maxM=100;
dx:array[1..4] of integer=(-1,1,0,0);
dy:array[1..4] of integer=(0,0,1,-1);
{Len,xuong,phai,trai}
VAR a:array[0..maxM+1,0..maxM+1] of CHAR;
CX:array[0..maxM+1,0..maxM+1] of boolean;
m,n,p,q,k,h:integer;
f,g:text;
{---------Thu tuc try---------}
PROCEDURE TRY(X1,Y1,X2,Y2:integer);
var i:integer;
begin
for i:=1 to 4 do {xet 4 vi tri xung quanh diem (X1,Y1)}
if (a[X1+dx[i],Y1+dy[i]]=a[X1,Y1]) and (CX[X1+dx[i],Y1+dy[i]])
then
begin
CX[X1+dx[i],Y1+dy[i]]:=FALSE;
IF (X1+dx[i]=X2) AND (Y1+dy[i]=Y2) THEN
BEGIN
ASSIGN(G,Fo);append(g);
WRITELN(G,'1');
CLOSE(G);
END
ELSE
TRY(X1+dx[i],Y1+dy[i],X2,Y2);
end;
end;
{---------Thu tuc vua doc va xu ly---------}
Procedure doc_XULY;
var i,j:integer;
begin
21
assign(f,fi);reset(f);
readln(f,M,n);
fillchar(a,sizeof(a),0); {Tao mang a toan so 0}
for i:=1 to M do
begin for j:=1 to N do read(f,a[i,j]);
readln(f);
end;
FILLCHAR(CX,SIZEOF(CX),TRUE);
WHILE NOT EOF(F) DO
BEGIN
readln(f,p,q,K,H);
cx[p,Q]:=false;
TRY(P,Q,K,H);
if cx[K,H] then
begin assign(g,fo); append(g); writeln(G,'0');close(g);end;
FILLCHAR(CX,SIZEOF(CX),TRUE); {sua lai trang thai ban dau cho
mang cx}
END;
close(f);
end;
BEGIN clrscr; doc_XULY; END.
3.2.3. Trò chơi Sukudo
Sukudo là trò chơi đã thịnh hành từ lâu và rất phổ biến. Sudoku là một loại trò
chơi lôgic và cách chơi là điền số từ 1 đến 9 vào những ô trống sao cho mỗi cột dọc,
mỗi hàng ngang, mỗi phân vùng nhỏ (ô 3x3) có đủ các số từ 1 đến 9 mà không được
lặp lại.
Bảng câu đố hình vuông, mỗi chiều có 9 ô nhỏ, hợp thành 9 cột, 9 hàng và được
chia thành 9 ô lớn 3x3. Một vài ô nhỏ được đánh số, đó là những manh mối duy nhất
để bạn tìm lời giải. Tuỳ theo mức độ nhiều hay ít của các manh mối, các câu đố
được xếp loại dễ, trung bình, khó hay cực khó. Ngoài ra, còn những bảng như
16x16, 25x25 hay thậm chí 100x100.
22
3
6
4
1
9
2
8
7
5
1
5
9
7
8
3
2
6
4
2
8
7
4
5
6
9
1
3
6
9
1
2
4
5
7
3
8
8
2
5
3
7
1
4
9
6
7
4
3
8
6
9
5
2
1
4
1
2
5
3
7
6
8
9
9
3
8
6
2
4
1
5
7
5
7
6
9
1
8
3
4
2
Một ví dụ về trò chơi Sudoku
Ở đây tôi muốn đề cập tới việc giải SUKUDO kích thước 9x9 ở mức độ dễ bằng
quay lui. Để giải trò chơi này ta cần có:
- Mảng a: lưu bảng khởi tạo ban đầu.
- Mảng ah: ah[i,j]=true, nếu số j đã có trong hàng i, ngược lại ah[i,j]=false
- Mảng ac: ac[i,j]=true, nếu số j đã có trong cột i, ngược lại ac[i,j]=false
- Mảng 3 chiều ac: dùng để lưu việc kiểm tra số i nào đó thuộc vùng kích thước
(3x3) nào. Nếu đã có trong vùng đó thì av[xv,yv, i] nhận giá trị true, ngược lại nhận
giá trị false.
Trong khi đọc dữ liệu từ tệp văn bản chứa dữ liệu vào là bảng trò chơi ban đầu,
nếu giá trị tại ô nào đó khác 0 thì ta xác định lại trạng thái của các ô trong ma trận
ah, ac và av.
Việc xác định số a[i,j] nào đó thuộc phân vùng (3x3) dựa vào công thức:
xv:=((i-1)div 3)+1;
yv:=((j-1)div 3)+1;
Trong đó xv là chỉ số dòng của vùng, yv là chỉ số cột của vùng (1≤xv, yv≤3).
Thủ tục Try(x,y,stop) : Sẽ thử đặt lần lượt các số từ 1 - 9 vào ô ở hàng x, cột y,
nếu vẫn còn ô trống - ô chưa được đặt số nào.
23
- Tìm ô trống đầu tiên, xác định ô đó thuộc phân vùng (3x3) nào bằng công thức ở
trên.
- Duyệt các số i chạy từ 1 – 9 nếu số đó chưa thuộc hàng x, chưa thuộc cột y và
phân vùng (xv, yv) thì ghi nhận thử số i này vào ô trống đó.
- Nếu ô trống này là ô cuối cùng của cột cuối, hàng cuối thì kết thúc việc điền các
giá trị. Ngược lại chưa phải hàng cuối thì gọi thủ tục Try cho ô ở cột đầu tiên của
dòng tiếp theo tức là Try(x+1,1,stop), chưa phải là cột cuối thì gọi thủ tục Try
cho vị trí ô kế tiếp cùng hàng tức là Try(x,y+1,stop) .
- Lặp đi lặp lại quá trình trên với các ô trống mới, nếu chưa giải ra thì quay lui để
điền lại các khả năng khác. Đồng thời đánh dấu lại trạng thái ở các mảng a, ah, ac và
av.
Cài đặt chương trình:
program sudoku;
uses crt;
var
a:array[1..9,1..9] of byte;
ah,ac:array[1..9,1..9] of boolean;
av:array[1..3,1..3,1..9] of boolean;
stop:boolean;
{----------------------------------------}
procedure DOCTEP;
var f:text; i,j,xv,yv,k:byte;
begin
assign(f,'sudoku.inp');
reset(f);
for i:=1 to 9 do
for j:=1 to 9 do
begin
read(f,a[i,j]);
if a[i,j]0 then
begin
xv:=((i-1)div 3)+1;
yv:=((j-1)div 3)+1;
24
ah[i,a[i,j]]:=true; {so a[i,j] da co trong hang i}
ac[j,a[i,j]]:=true;
{so a[i,j] da co trong cot j}
av[xv,yv,a[i,j]]:=true; {so a[i,j] da co trong phan vung
(3x3) xc,yc}
end;
end;
close(f);
end;
{----------------------------------------}
Procedure INKQ;
var i,j:byte; f:text;
begin
assign(f,'sudoku.out');rewrite(f);
for i:=1 to 9 do
begin
for j:=1 to 9 do
write(f,a[i,j],' ');
writeln(f);
end;
close(f);
end;
{----------------------------------------}
Procedure Try(x,y:byte;var stop:boolean);
var
i,xv,yv:byte; ktra:boolean;
begin
if a[x,y]0 then
begin
repeat
inc(y); {thu cot ke ben}
if y=10 then
begin {xuong hang ke tiep}
y:=1;
inc(x);
end;
stop:=x=10;
until(a[x,y]=0)or(stop);
if not(stop) then try(x,y,stop);
25
end
else
begin
xv:=((x-1)div 3)+1;
yv:=((y-1)div 3)+1;
{xét các chữ số từ 1 tới 9}
for i:=1 to 9 do if not(stop) then
begin {số đó chưa có trong hàng x, cột y, vùng (xv,yv)}
ktra:=(ah[x,i]=false)and(ac[y,i]=false)and(av[xv,yv,i]=false);
if ktra then
begin
a[x,y]:=i;
ah[x,i]:=true;
ac[y,i]:=true;
av[xv,yv,i]:=true;
if y=9 then
if x=9 then stop:=true
else try(x+1,1,stop)
else try(x,y+1,stop);
if (not(stop)) then
begin
a[x,y]:=0;
ah[x,i]:=false;
ac[y,i]:=false;
av[xv,yv,i]:=false;
end;
end;
end;
end;
end;
{----------------------------------------}
Begin clrscr;
DOCTEP;
try(1,1,stop);
if stop then INKQ;
readln
End.
26
KẾT LUẬN
Một bài toán có thể được giải quyết bằng nhiều thuật toán khác nhau. Đệ quy
quay lui là một trong những phương pháp tương đối hiệu quả. Lẽ dĩ nhiên quay lui
cũng có nhược điểm của nó. Đó là khi giải các bài toán với bộ dữ liệu lớn thì quay
lui tốn rất nhiều thời gian và khó khăn trong việc lưu trữ. Tuy nhiên không thể phủ
nhận quay lui là phương pháp giải các bài toán liệt kê khá hiệu quả và dễ hiểu đối
với trình độ của học sinh THPT, đặc biệt là trong các trường THPT không chuyên.
Từ những bài toán mà tôi nêu ở trên ta có thể thấy quay lui có thể giải quyết các bài
toán ứng dụng nhiều trong thực tế.
Trong các năm học vừa qua, tác giả đã chú tâm thực hiện việc hình thành phương
pháp giải các bài toán Tin học bằng đệ quy quay lui cho một số học sinh trong đội
tuyển thi học sinh giỏi Tỉnh của trường và thấy kết quả rất tốt. Tỷ lệ đạt học sinh
giỏi Tỉnh từ 33,3% trong năm học 2011 – 2012, sau khi áp dụng đề tài này đã tăng
lên 100% trong hai năm học 2012 – 2013 và 2013 – 2014. Học sinh hứng thú hơn
với môn Tin, kỹ năng lập trình cũng được nâng cao.
Do thời gian nghiên cứu còn ít, năng lực còn nhiều hạn chế nên đề tài chắc còn
nhiều khiếm khuyết. Tác giả rất mong muốn nhận được nhiều góp ý chân thành từ
các đồng nghiệp, các bạn đọc và các em học sinh để đề tài được hoàn thiện hơn, góp
phần nâng cao chất lượng dạy học Tin học.
Xin chân thành cảm ơn!
27
TÀI LIỆU THAM KHẢO
---------------------[1] Đỗ Xuân Lôi, Cấu trúc dữ liệu và giải thuật, Nhà xuất bản khoa học và kỹ
thuật.
[2] Hồ Sỹ Đàm (chủ biên), Tài liệu giáo khoa chuyên Tin, Nhà xuất bản giáo
dục Việt Nam.
[3] Lê Minh Hoàng, Giải thuật và lập trình, Đại học Sư phạm Hà Nội.
[4] Nguyễn Xuân Huy, Sáng tạo trong thuật toán và lập trình - Tập 1, Nhà
xuất bản giáo dục.
[5] Các tài liệu về Đệ quy quay lui trên Internet.
28
MỤC LỤC
29
[...]... then begin assign(f,fo);rewrite(f); 15 write(f,'Khong co duong di');close(f); end; END 3.2 Ứng dụng quay lui để giải một số bài toán xử lý trên mảng hai chiều kích thước MxN 3.2.1 Đếm số miền liên thông, miền liên thông lớn nhất a, Đề bài: Cho ma trận A cấp MxN, trên mỗi ô A[i,j] của lưới ghi số 0 hoặc 1 Hai ô được gọi là liên thông trực tiếp nếu nó chung cạnh và cùng giá trị 1, ngược lại có giá trị 0... Một bài toán có thể được giải quyết bằng nhiều thuật toán khác nhau Đệ quy quay lui là một trong những phương pháp tương đối hiệu quả Lẽ dĩ nhiên quay lui cũng có nhược điểm của nó Đó là khi giải các bài toán với bộ dữ liệu lớn thì quay lui tốn rất nhiều thời gian và khó khăn trong việc lưu trữ Tuy nhiên không thể phủ nhận quay lui là phương pháp giải các bài toán liệt kê khá hiệu quả và dễ hiểu đối... Ta có thể di chuyển từ vị trí máy phát sóng này đến vị trí máy phát sóng khác nếu hai máy phát sóng đó nằm trên hai mảnh đất ô vuông có cạnh chung Một vùng máy phát sóng là tập hợp các mảnh đất ô vuông có trên đó đặt các máy phát sóng phát ra loại sóng có cùng dãy tần số Việc xác định hai máy 19 phát sóng nào đó nằm trên hai mảnh đất ô vuông có cùng một vùng phát sóng tại một thời điểm phát sóng nào... Sudoku Ở đây tôi muốn đề cập tới việc giải SUKUDO kích thước 9x9 ở mức độ dễ bằng quay lui Để giải trò chơi này ta cần có: - Mảng a: lưu bảng khởi tạo ban đầu - Mảng ah: ah[i,j]=true, nếu số j đã có trong hàng i, ngược lại ah[i,j]=false - Mảng ac: ac[i,j]=true, nếu số j đã có trong cột i, ngược lại ac[i,j]=false - Mảng 3 chiều ac: dùng để lưu việc kiểm tra số i nào đó thuộc vùng kích thước (3x3) nào... ô xung quanh (Trên, dưới, phải, trái) của nó Vì thế sử dụng 2 hằng mảng một chiều thể hiện độ biến thiên của hàng, cột: 16 dx:array[1 4] of integer=(-1,1,0,0); dy:array[1 4] of integer=(0,0,1,-1); {Trên, dưới,phải,trái} Ta sẽ xét tất cả các ô có trong lưới MxN nếu có giá trị là 1 và chưa được xét thì ghi nhận có một miền liên thông Để xác định ô đã được xét hay chưa ta dùng một mảng hai chiều b Ban đầu... học sinh THPT, đặc biệt là trong các trường THPT không chuyên Từ những bài toán mà tôi nêu ở trên ta có thể thấy quay lui có thể giải quyết các bài toán ứng dụng nhiều trong thực tế Trong các năm học vừa qua, tác giả đã chú tâm thực hiện việc hình thành phương pháp giải các bài toán Tin học bằng đệ quy quay lui cho một số học sinh trong đội tuyển thi học sinh giỏi Tỉnh của trường và thấy kết quả rất... − Các dòng tiếp theo, mỗi dòng ghi 4 số mô tả vị trí của hai mảnh đất ô vuông mà ta cần kiểm tra chúng có cùng một vùng phát sóng hoặc không 2 số đầu ghi thứ tự dòng và số thứ tự cột của mảnh đất ô vuông thứ nhất, 2 số sau là thứ tự dòng và số thứ tự cột của mảnh đất ô vuông thứ hai − Các ký tự trên cùng một dòng được ghi liên tiếp nhau Các số trên cùng một dòng được ghi cách nhau ít nhất một ký tự... Try(x+1,1,stop), chưa phải là cột cuối thì gọi thủ tục Try cho vị trí ô kế tiếp cùng hàng tức là Try(x,y+1,stop) - Lặp đi lặp lại quá trình trên với các ô trống mới, nếu chưa giải ra thì quay lui để điền lại các khả năng khác Đồng thời đánh dấu lại trạng thái ở các mảng a, ah, ac và av Cài đặt chương trình: program sudoku; uses crt; var a:array[1 9,1 9] of byte; ah,ac:array[1 9,1 9] of boolean; av:array[1... sóng trong lần phát sóng kế tiếp Cho trước vị trí của hai mảnh đất ô vuông, hãy xác định hai mảnh đất đó có cùng một vùng phát sóng tại một thời điểm phát sóng nào đó hay không? Dữ liệu vào là tệp văn bản TSPS.INP có cấu trúc: − Dòng đầu tiên ghi 2 số M, N (1≤M≤100, 1≤N≤100) − M dòng tiếp theo, mỗi dòng ghi N ký tự ‘A’ hoặc ‘B’ nếu máy phát sóng đặt trên mảnh đất ô vuông tương ứng phát sóng loại sóng... dục Việt Nam [3] Lê Minh Hoàng, Giải thuật và lập trình, Đại học Sư phạm Hà Nội [4] Nguyễn Xuân Huy, Sáng tạo trong thuật toán và lập trình - Tập 1, Nhà xuất bản giáo dục [5] Các tài liệu về Đệ quy quay lui trên Internet 28 MỤC LỤC 29 ... thử chương trình: Dưới đường quân mã: Ứng dụng quay lui để giải số toán xử lý mảng hai chiều 3.1 Ứng dụng quay lui để giải số toán xử lý mảng hai chiều kích thước NxN 3.1.1 Kiểm tra có đường đỉnh... thức đệ quy quay lui (Back tracking) Bài toán kinh điển: Mã tuần Ứng dụng quay lui để giải số toán xử lý mảng hai chiều Kết luận PHẦN II: PHẦN NỘI DUNG Nhắc lại kiến thức đệ quy quay lui (Back... đệ quy quay lui − Áp dụng giải với số toán cụ thể IV Đối tượng nghiên cứu: Đối tượng nghiên cứu đề tài đệ quy quay lui ứng dụng quay lui để giải toán Tin học có liên quan tới mảng hai chiều tài