Thuật toán quay lui DOMINO
Trang 1Thuật toán quay lui và ứng dụng
Lã Văn Chinh
Giả thiết một cấu hình cần tìmđược mô tả bởi một bộ phận gồm n thành phần a1, a2,
an Giả sử tìm được i -1 thành phần a1, a2, ai-1, ta tìm thành phần thứ i bằng cách duyệt tất cả cáckhả năng có thể của ai Với mỗi khả năngj kiểm tra xem nó có chấp nhận được không Xảy ra hai trường hợp
Nếu j chấo nhận được thì xác định ai theo j và kiểm tra xem i = n chưa, nếu i = n thì ta ghi nhận một cấu hình, còn nếu i < nta gọi tiến hành xác định ai+1
Nếu thử tất cả các khả năng mà không có khả năng nào chấp nhận được thì quay lại bước trước xác định lại ai-1
Nội dung của thuật toán này rấtphù hợp với việc gọi đệ quy Ta có thủ tục đệ quy sau đây:
Procedure Try (i:tinteger);
Var j:integer;
Begin
For j:=1 to n do
if chấp nhận j then
begin
xác nhận aj theo j
if i=n then < ghi nhận cấu hình >
else try(i+1);
end;
end;
Để minh hoạ cho thuật toán này ta áp dụng giải bài toán xếp hậu:
Nội dung bài toán: Liệt kê tất cả các cách sắp xếp những con hậu trên bàn cờ NxN sao
cho chúng không ăn được nhau
Trang 2Giải: Ta xếp n con hậu trên n dòng, heo nguyên lý nhân ta có nn cách sắp xếp thoả mãn điều kiện đầu bải Để làm điều đó ta dùng thủ tục đệ quy mô tả ở trên để giải.Ta đánh ghi
số cột và dòng của bàn cờ từ 1 đến n, mỗi cách sắp xếp ứng với 1 bộ gồm a1,a2, ,an
vớiai = j (j=1,2, ,n) có nghĩa là con hậu thứ i đặt vào cột j Giả sử ta chọn được i-1 con hậu bằng cách duyệt tất cả các khả năng của nó
Quan trọng nhất là ta tìm điều kiện chấp nhận j, một con hậu đứng ở một ô trong bàn cờ
nó có nhiều nhất bốn hướng đi (đường dọc, đường ngang và hai đường chéo)
Vậy điều kiện chấp nhận thứ i thoả mãn không nằm trên đường đi của tất cả i-1 con hậu
đã xếp.Bởi vì n con hậu xếp ở hàng nên đường đi ngang của chúng là không chiến nhau,
do đó khi chọn con hậu thư ichỉ cần kiểm tra xem trên 2 đường chéo và đường dọc của chúng có chiếu vào những con hậu đã xếp không Để kiểm tra điều này mỗi đường ta dùng một biến trạng thái
* Đường dọc kiểm soát bằng biến b[j],(j=1,2, ,n)
* Một đường chéo kiểm soát bằng biến c[i+j],i+j={2, ,2n}
* Còn đường chéo kia kiểm soát bằng biến d[i-j],i-j={1-n, ,n-1}
Các biến trạng thái này khởi gán giá trị True trong thủ tục Init Như vậy con hậu thứ i
được chấpnhận xếp vào cột j nếu nó thoả mãn cả ba biến b[j],c[i+j],d[i-j] đều có giá trị true.Các biến này gán giá trị False khi xếp xong con hậu thứ i, và trả lại giá trị true sau khi gọi Resulthay Try(i+1) Ta có chương trình Pascal sau :
Program XepHau;
Uses crt;
var n : integer;
a:array[1 30] of integer;
b:array[1 30] of boolean;
c:array[2 60]of boolean;
count,d:word;
Procedure Init;
Var i:integer;
Begin
Trang 3Write('Cho do rong ban co n= '); Readln(n);
Count:=0; d:=0;
For i:=1 to n do b[i]:=true; For i:=2 to 2*n do c[i]:=true; For i:=1-n to n-1 do d[i]:=true; End;
Procedure Result;
Var i:integer;
Begin
d:=d+1; count:=count+1;
Write('Cach xep thú,count:5,'.'); for i:=1 to n do write(a[i]:2); Writeln;
if d = 24 then
begin
readln; d : = 0;
end;
end;
Procedure try(i:integer);
Var j : integer;
Begin
For j:=1 to n do
Trang 4If (b[j]) and (c[i + j]) and (d[i- j]) then
Begin
a [i] : = j;
b [j] : = false; c[i + j]: = false;
d [i] : = false;
if i = n then Result else try(i+1);
b [j] : = true; c[i + j]: = true;d[i + j]: = true;
end;
end;
begin
clrscr;
Init;
Try(1);
Write ('An Enter de ket thuc:');
Readln;
End
Để hiểu sâu sắc thuật toán này, mời bạn đọc làm một số bài toán sau:
Bài 1: Hãy viết chương trình liệt kê tất cả các dãy nhị phân có độ dài n
Bài 2: Hãy viết chương trình liệt kê các hoán vị của {1,2, ,n}
Bài 3: Hãy viết chương trình liệt kê các tổ hợp chập m của {1,2, ,n}
Bài 4: Hãy viết chương trình liệt kê tất cả các chu trình Haminton của đồthị
(Chu trình bắt đầu từ đỉnh v nào đó qua tất cả các đỉnh còn lại, mỗiđỉnh đúng một lần rồi quay trở về đỉnh v được gọi là chu trình Hamilton)