Thuật toán quay lui và ứng dụng
Chia sẻ bởi Tôn Nữ Bích Vân |
Ngày 14/10/2018 |
27
Chia sẻ tài liệu: Thuật toán quay lui và ứng dụng thuộc Tư liệu tham khảo
Nội dung tài liệu:
Thuật toán quay lui và ứng dụng
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ác khả năng có thể của ai. Với mỗi khả năng j kiểm tra xem nó có chấp nhận được không. Xảy rahai trường hợp.
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 < ta 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ất phù 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
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.
Giải: Ta xếp n con hậu trên n dòng, Theo 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ới ai = 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ư i chỉ 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ấp nhậ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 Result hay 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
Write(`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 thu`,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:=
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ác khả năng có thể của ai. Với mỗi khả năng j kiểm tra xem nó có chấp nhận được không. Xảy rahai trường hợp.
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 < ta 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ất phù 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
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.
Giải: Ta xếp n con hậu trên n dòng, Theo 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ới ai = 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ư i chỉ 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ấp nhậ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 Result hay 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
Write(`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 thu`,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:=
* Một số tài liệu cũ có thể bị lỗi font khi hiển thị do dùng bộ mã không phải Unikey ...
Người chia sẻ: Tôn Nữ Bích Vân
Dung lượng: 32,50KB|
Lượt tài: 0
Loại file: doc
Nguồn : Chưa rõ
(Tài liệu chưa được thẩm định)