Cùng chia sẻ những bài toán hay qua thuật toán duyệt đệ quy
Nguyễn Công Cường
Khi tiếp xúc với một bài toán, ít ai trong chúng ta nghĩ ngay đến phương pháp duyệt, mà ta
luôn tìm đến những thuật toán mạnh hơn như: Quy hoạch động,cặp ghép… Bởi lẽ, vốn dĩ
Duyệt thường không khả thi do tập hợp cáccấu hình cần duyệt là rất lớn. Tuy nhiên, không
phải lúc nào cácthuật toán mạnh cũng cho ra lời giải tốt nhất. Mà đôi khi trong mộtsố
trường hợp Duyệt lại là phương án tối ưu.
Nhưng phải duyệt như thế nào để vét cạn tất cả các trường hợp và hạn chếđược khối lượng
các cấu hình cần duyệt lại là những câu hỏi tươngđối nhức đầu đặt ra cho chúng ta. Sau
đây, tôi xin giới thiêụ mộtsố bài toán hay sử dụng phương pháp đệ quy để duyệt.
Bài toán 1. Xoay ô.
Cho một hình vuông gồm n*n ô, mỗi ô nhận được một trong 4 trạng thái sau:
Trạng thái của mỗi ô có thể thay đổi bằng cách xoay ô đó theo chiều kim đồnghồ một trong
những góc 90
o
, 180
o
, 270
o
.
Một hình vuông được gọi là hợp lệ nếu trong hình vuông bất kỳ 2 ô chung cạnhthì không
chung màu.
Ví dụ:
Yêu cầu: Tìm cách xoay ít ô nhất để hình vuông đã cho trở thành hợp lệ.
Dữ liệu vào: ″XOAY.INP″.
Dòng đầu gồm n dòng, n dòng tiếp theo mỗi dòng ghi trạng thái của hình chữ nhật.
Kết quả:Ghi ra fiel″XOAY.OUT″.
Nếu không cần xoay thì ghi ′0′. Ngược lại ghi m −là số ô cần xoay. m dòngtiếp theo mỗi
dòng ghi toạ độ ô cần xoay và góc xoay.
Ví dụ:
XOAY.INP
4
2 0 1 0
2 0 3 2
2 0 2 3
1 2 1 0
XOAY.OUT
6
1 1 270
2 1 270
2 3 180
2 4 180
3 2 270
4 2 180.
Thuật toán:
Nhận thấyrằng: Nếu ô chéo nhau và liền dưới nhau đã biết thì 2 ô kề cạnh vớicả 2 ô đó là
xác định duy nhất.
Ví dụ:
Trong trườnghợp này: Để được hình vuông hợp lệ thì:
- Ô [1,2] bắtbuộc phải mang trạng thái 0
- Ô [2,1]nhất thiết phải mang trạng thái 1
Như vậy, mộthình vuông sẽ hoàn toàn xác định nếu ta đã biết trạng thái của cácô nằm trên
đường chéo chính từ ô [1,1] đến ô [n,n].
Từ hình 1:Có duy nhất một hình vuông hợp lệ xây dựng được là:
Vậy, từ pháthiện trên, ta chỉ phải duyệt các ô nằm trên đường chéo chính củahình vuông,
mỗi ô 4 trạng thái và cập nhật lại kỉ lục mỗi khi xâydựng được một hình vuông hợp lệ.
Chương trình;
ProgramXoay_o;
Constfi = ′Xoay.inp′;
fo=′Xoay.out′;
tren:array[0..3,0..3] of byte= ((0,1,1,0),(0,1,1,0),(3,2,2,3), (3,2,2,3));
Duoi:Array[0..3,0..3] of byte = ((0,0,3,3),(1,1,2,2),(1,1,2,2), 0,0,3,3));
Var a,c,l:array[1..10,1..10] of byte;
Sl,kl:Integer;
N: Byte; f:Text;
Procedureinput;
Var i,j:Integer;
Begin
Assign(f,fi);
Reset(f);
Readln(f,n);
For i:=1 to n do
For j:=1 to n do
Readln(f,a[i,j]);
Close(f);
End;
Procedurekhoi_tao;
Begin
Sl:=0; Kl:=maxint;
Fillchar(c,sizeof(c),0);
End;
ProcedureQlui(i: integer);
Var j,k,dem:integer;
Begin
If i>n then
Begin
If sl
Begin
Kl:=sl; L:=c;
End;
End
Else
Begin
For j:=0 to 3 do
Begin
Dem:=0;
C[i,i]:=j;
If c[i,i]<>a[i,i] then inc(dem);
For k:=i-1 downto 1 do
Begin
C[k,i]:=Tren[c[k,i-1],c[k+1,i]];
C[i,k]:=Duoi[c[i-1,k],c[i,k+1]];
Ifc[k,i]<> a[k,i] then inc(dem);
Ifc[i,k]<>a[i,k] then inc(dem);
End;
Sl:=sl+dem;Qlui(i+1);
Sl:=sl-dem;
End;
End;
End;
Procedureoutput
Var i,j,t: integer;
Begin
Assign(f,fo);
Rewrite(f);
Writeln(f,kl);
If kl<>0 then
For i:=1 to n do
For j:=1 to n do
If l[i,j]<> a[i,j] then
Begin
Write(f,i,′′,j,′ ′);
T:=(l[i,j]-a[i,j]+4) mod 4;
Writeln(f,t*90);
End;
Close(f);
End;
Proceduremain;
Begin
Khoi_tao; Qlui; Output;
End;
BEGIN
Input;
Main;
END.
Bài toán 2. Robot quét vôi
Có 9 cănphòng (đánh số từ 1 đến 9) đã được quét vôi với mầu trắng, xanhhoặc vàng. Có 9
robot (được đánh số từ 1 đến 9) phụ trách việc quétvôi các phòng. Mỗi robot chỉ quét vôi
một số phòng nhất định. Việcquét vôi được thực hiện nhờ một chương trình cài sẵn theo
quy tắcsau:
- Nếu phòng đang có màu trắng thì quét màu xanh.
- Nếu phòngđang có màu xanh thì quét màu vàng.
- Nếu phòngđang có màu vàng thì quét màu trắng.
Cần phải gọilần lượt một số các robot ra quét vôi (mỗi lần một robot, một robotcó thể gọi
nhiều lần và cũng có thể không được gọi. Robot đượcgọi quét vôi tất cả các phòng mà nó
phụ trách). Hãy tìm một phươngán như vậy, sao cho lượng vôi phải quét là ít nhất. Giả
thiết rằnglượng vôi cho mỗi lượt quét với mỗi phòng là như nhau.
Dữ liệu vào: ROBOT.INP
9 dòng đầutiên liệt kê danh sách các phòng (viết liền nhau) mà robot thứ i (i=1..9) phụ
trách.
Dòng cuốimô tả màu vôi ba đầu của các phòng với quy ước:
X- xanh; V− vàng; T - trắng.
Kết quả:
Ghi ra file″ROBOT.OUT″ gồm 1 dòng dưới dạng:
- Nếu khôngcó phương án thì ghi ″0″.
- Ngược lạighi dãy thứ tự các Robot được gọi.
Ví dụ:
ROBOT.INP
159
123
257
147
5
369
456
789
258
XVXVXVTXT.
Thuật toán: ở bài này, ta lại thấy rằng: thứ tự gọi robot ta quét vôi có tínhchất giao hoán,
nghĩa là robot thứ i dù được gọi trước hay sau đềukhông ảnh hưởng đến kết quả nhận
được.
Ví dụ: Nếudanh sách các robot được gọi là 121 thì ta cũng có thể gọi theo thứtự: 112 − kết
quả không hề thay đổi.
Như vậy: mộtrobot nếu được gọi đến lần thứ 3 thì ta có thể bỏ robot đó ra khỏidanh sách,
tức là nếu muốn nhận được kết quả tối ưu thì mỗi robotphải không được gọi quá 2 lần, từ
đó ta có thể đưa ra chương trìnhnhư sau:
Chương trình:
{$M65000,0,65000}
Programrobot_quet_voi;
Constfi=′Robot.inp′;
fo=′Robot.out′;
Typemang=array[1..9] of byte;
Var Rb:array[1..9] of mang;
a,d,luu:mang;
s,kq:string;
kl,sl:integer;
f:text;
ProcedureInput;
Vari,j: integer; Ch: char;
Begin
Assign(f,fi);
Reset(f);
For i:=1 to 9 do
Begin
J:=0;
While not eofn(f) do
Begin
Read(f,cj);
If ch<> #13 then
Begin
Inc(j);
Rb[i][j]:=ord(ch)-48;
End;
End;
d[i]:=j; read(f,s);
close(f);
End;