Chương 6 Giải thuật quay lui
Giải thuật quay lui Giải thuật nhánh-và-cận
1
ể ả ế ấ ề i quy t v n đ : thi
ằ ị ế t ả i cho bài tóan không ph i là bám c xác đ nh mà là b ng
ử
Giải thuật quay lui ươ ổ ộ ng pháp t ng quát đ gi M t ph ờ ả ậ ế ả i gi i thu t tìm l k gi ượ ậ ộ ậ theo m t t p qui lu t tính tóan đ ử (trial and error). cách th và s a sai
ườ ử ng là phân rã quá trình th và s a
ườ theo l
ữ ộ ậ ệ ử ữ i đ quy m t ộ ố ữ ạ ượ ồ ng thì nh ng ễ ả ộ ố ệ ệ thăm dò m t s h u h n
ữ ẫ Khuôn m u thông th ộ ậ sai thành nh ng công tác b ph n. Th công tác b ph n này đ c di n t ậ cách thu n ti n và bao g m vi c nh ng công tác con .
ể ư ộ
ầ ấ ạ ệ ầ
2
ộ ộ quá trình Ta có th coi toàn b quá trình này nh là m t tìm ki mế (search process) mà d n d n c u t o và duy t qua m t cây các công tác con.
Bài toán đường đi của con hiệp sĩ (The Knight’s Tour Problem)
ộ ượ ờ n (cid:0) ộ n v i ớ n2 ô. M t con hi p sĩ – đ
ể ậ ệ ượ ặ c di ở c đ t trên bàn c
ầ Cho m t bàn c chuy n tuân theo lu t ch i c vua – đ ạ t i ô đ u tiên có t a đ x ơ ờ ọ ộ 0, y0.
ấ ộ ướ phủ
ề ộ trình ượ ờ c sao cho ộ ầ ế ộ l V n đ là tìm m t ỗ toàn b bàn c (m i ô đ g m ồ n2 –1 b c vi ng đúng m t l n).
ể ả ủ 2 ô là xét bài toán,
Cách rõ ràng đ thu gi m bài toán ph n ho c làặ
ệ ướ ự th c hi n b ế ế c đi k ti p, hay
3
ệ ằ ế ợ ệ phát hi n r ng không ki m đ ượ ướ c b c đi h p l nào.
4
procedure try next move; begin initialize selection of moves; repeat select next candidate from list of next moves; if acceptable then begin record move; if board not full then begin (6.3.1) try next move; if not successful then erase previous recording end end until (move was successful) (cid:0) (no more candidates) end
Cách biểu diễn dữ liệu
ễ ả ờ ằ ộ Chúng ta di n t bàn c b ng m t ma tr n ậ h.
ượ ô
type index = 1..n ; var h: array[index, index] of integer; ư ề ượ h[x, y] = 0: ế h[x, y] = i: c vi ng t i (1(cid:0) i (cid:0) n2)
ệ ể ượ ễ ả ằ c di n t b ng “i <
ề Đi u ki n “board not full” có th đ n2”.
ế ọ ộ ủ u, v: t a đ c a ô đ n.
ệ ề ể ượ ễ ả ằ c di n t b ng
5
Đi u ki n “acceptable” có th đ (1(cid:0) u(cid:0) n) (cid:0) (1(cid:0) v(cid:0) n) (cid:0) (h[u,v]=0)
(6.3.2)
q1 then h[u,v]:=0
6
procedure try(i: integer; x,y : index; var q: boolean); var u, v: integer; q1 : boolean; begin initialize selection for moves; repeat let u, v be the coordinates of the next move ; if (1(cid:0) u(cid:0) n) (cid:0) (1(cid:0) v(cid:0) n) (cid:0) (h[u,v]=0) then begin h[u,v]:=i; if i < sqr(n) then begin try(i + 1, u, v, q1); if (cid:0) end else q1:= true end until q1 (cid:0) (no more candidates); q:=q1 end
ọ ộ ủ ệ
ố ừ ượ ớ ể ả c đánh s t
3
2
4
1
ể ọ
Cho t a đ c a ô hi n hành
5
8
6
7
7
(cid:0)
Sự tinh chế sau cùng
ơ c t a đ
ạ ộ ạ ệ ằ ả Cách đ n gi n nh t đ đ t đ ọ b ng cách c ng đ sai bi ấ ể ạ ượ ọ ộ u, v t ộ t to đ t i hai m ng ừ x, y là ả a và b.
ượ ế ế ố ứ ể Và k đ c dùng đ đánh s ng viên (candidate) k ti p.
8
program knightstour (output); const n = 5; nsq = 25; type index = 1..n var i,j: index; q: boolean; s: set of index; a,b: array [1..8] of integer; h: array [index, index] of integer;
q1 then h[u,v]:=0
procedure try (i: integer; x, y: index; var q:boolean); var k,u,v : integer; q1: boolean; begin k:=0; repeat k:=k+1; q1:=false; u:=x+a[k]; v:=y+b[k]; if (u in s) (cid:0) (v in s) then if h[u,v]=0 then begin h[u,v]:=i; if i < nsq then begin try(i+1, u,v,q1); if (cid:0) end else q1:=true end until q1 (cid:0) (k =8); q:=q1 end {try};
9
h[1,1]:=1; try (2,1,1,q); if q then for i:=1 to n do begin for j:=1 to n do write(h[i,j]:5); writeln end else writeln (‘NO SOLUTION’) end.
10
begin s:=[1,2,3,4,5]; a[1]:= 2; b[1]:= 1; a[2]:= 1; b[2]:= 2; a[3]:= –1; b[3]:= 2; a[4]:= –2; b[4]:=1; a[5]:= –2; b[5]:= –1; a[6]:= –1; b[6]:= –2; a[7]:= 1; b[7]:= –2; a[8]:= 2; b[8]:= –1; for i:=1 to n do for j:=1 to n do h[i,j]:=0;
ở ộ
ọ ớ ọ ộ
ở ầ
ệ
ằ
ượ
ủ ụ ệ
0,
c kh i đ ng b ng l nh g i v i t a đ kh i đ u x ắ ầ
ế
ừ
đó chuy n đi b t đ u.
H[x0,y0]:= 1; try(2, x0, y0, q)
ộ ờ
ả ạ ượ ớ ị
ớ
Th t c đ quy đ y0 , t Hình 6.3.1 trình bày m t l
i gi
c v i v trí <1,1> v i n = 5.
i đ t đ
1
6
15
10
21
14
9
20
5
16
19
2
7
22
11
8
13
24
17
4
25
18
3
12
23
11
ụ
ế ớ ộ
ể
ả
ế
i quy t
ớ
ừ T thí d trên ta đi đ n v i m t ki u “gi ề ấ v n đ ” m i:
ể
ặ
Đ c đi m chính là
ề ờ ả ầ ủ
ng v l
i đ y đ và ghi l
ướ ướ c h ề ướ
ị
i gi c này mà sau đó nó có th
ướ
ệ ằ ế ờ ả ầ ủ ứ
ộ ướ
i đ y đ , t c là m t b
ạ “b i thông ỡ và ể b tháo g tin v b ẫ xóa đi khi phát hi n r ng b c này đã không d n ế ẫ i gi đ n l c đi d n đ n ượ ọ ế ế ắ ”(deadend). (Hành vi này đ c g i “tình th b t c là quay lui bactracking.)
12
Khuôn mẫu tổng quát của giải thuật quay lui
13
procedure try; begin intialize selection of candidates; repeat select next; if acceptable then begin record it; if solution incomplete then begin try next step; (6.3.3) if not successful then cancel recording end end until successful (cid:0) no more candidates end
ế ạ ỗ ướ ố ứ
ể
ư i m i N u t c, s ng b ử ả viên ph i th là ố ị c đ nh thì ki u ể ẫ m u trên có th ế ổ bi n đ i nh :
(cid:0)
ệ
ủ ụ ượ c Th t c đ ọ ằ g i b ng l nh g iọ
try(1).
procedure try (i: integer);
var k : integer;
begin k:=0;
repeat
k:=k+1; select k-th candidate;
if acceptable then
begin
record it;
if i
14
Bài toán 8 con hậu
ượ
ả
c C.F. Gauss kh o sát năm 1850,
ư
ả
ế ượ
Bài toán này đã đ
nh ng ông ta không hoàn toàn gi
i quy t đ
c.
ậ
ờ
ậ ượ ặ
“Tám con h u đ
c đ t vào bàn c sao cho không
ể ấ
ậ
có con h u nào có th t n công con h u nào
”.
ượ
hình 6.3.1, ta s có đ
ộ
c m t
ủ ụ
ậ
ẽ
ẫ ở
Dùng khuôn m u
th t c sau cho bài toán 8 con h u:
15
procedure try (i: integer);
begin
initialize selection of positions for ith queen;
repeat
make next selection;
if safe then
begin
setqueen;
if i < 8 then
begin
try (i + 1);
if not successful then remove queen
end
end
until successful (cid:0) no more positions
end
16
ộ
ậ
ể ấ
ằ
ậ
Lu t c :
ộ ộ
ườ
ậ ờ M t con h u có th t n công các con h u khác n m trên
ờ
ng chéo trên bàn c .
ễ ữ ệ
ộ
ể
cùng m t hàng, cùng m t c t hay là cùng đ
Cách bi u di n d li u
var x: array[1..8] of integer;
a: array[1..8] of Boolean;
b: array[b1..b2] of Boolean;
c: array[c1..c2] of Boolean;
ể ễ ả ậ Làm cách nào đ di n t ờ
8 con h u trên bàn c ?
v iớ
ỉ ị ủ ộ ậ
x[i] ch v trí c a con h u trên c t th
ứ i;
ế a[j] cho bi ậ
t không có con h u trên hàng th ứ j;
ế ậ ườ b[k] cho bi t không có con h u trên đ ng chéo th ứ k;
th ứ k.
17
ế ậ ườ c[k] cho bi t không có con h u trên đ ng chéo
ệ
ọ
ở
ấ ả
ẽ
t c các ô s có cùng giá tr c a
ộ ườ
ọ ộ i +j, và trên cùng m t đ
ượ
c xác
ả b và c
ộ ườ
ng
ị ủ
ng chép
ị ủ
ấ ả
ẽ
t c các ô s có cùng giá tr c a
ệ
ị
ố b1, b2, c1, c2 đ
Vi c ch n tr cho các m c
ỉ ố ủ
ị
đ nh b i cách mà các ch s c a các m ng
ằ
ượ
c tính. Hãy chú ý r ng trên cùng m t đ
đ
chéo chi u ề t
ổ
t ng hai t a đ
chi u ề diagonal, t
hi u hai t a đ (
ọ ộ i – j ).
ượ
ư ậ
ế ư
c tinh ch nh
ể setqueen đ
c ượ chi ti
ư ế
ề
ễ ả ư
ượ
nh sau:
c di n t
18
Nh v y, phát bi u
sau:
x[i]:=j; a[j]:=false; b[i+j]:=false;c[ij]:=false;
Phát bi u ể removequeen đ
:
t hóa nh sau
a[j] = true; b[i+j] = true ; c[ij] := true
Đi u ki n
ệ safe đ
a[j] (cid:0) b[i+j] (cid:0) c[ij]
i : integer; q: boolean;
program eightqueeen1(output);
{find one solution to eight queens
problem}
var
a : array [1..8] of boolean;
b : array [2..16] of boolean;
c : array [–7..7] of boolean;
x : array [1..8] of integer;
procedure try(i: integer; var q:
boolean);
var j: integer;
begin
j:=0;
repeat
j:=j+1; q:=false;
if a[j] (cid:0) b[i+j] (cid:0) c[ij] then
begin
x[i]:=j;
a[j]:=false; b[i+j]:=false;
c[i-j]:=false;
if i<8 then
begin
try (i+1, q);
if (cid:0)
q then
begin
a[j]:=true; b[i+j]:=true;
c[i-j]:=true
end
end
else q:=true
end
until q (cid:0) (j=8)
end {try};
19
begin
for i:= 1 to 8 do a[i]:=true;
for i:= 2 to 16 do b[i]:=true;
for i:= –7 to 7 do c[i]:=true;
try (1,q);
if q then
for i:=1 to 8 do
write (x[i]:4);
writeln
end
ậ ượ ở ộ ờ ả ủ
i gi i c a bài toán 8 con h u đ c cho ẽ
hình v
20
M t l
sau:
H
1
H
2
H
3
H
4
H
5
H
6
H
7
H
8
21
Sự mở rộng: Tìm tất cả các lời giải
ự ở ộ
i gi
i mà t
ấ ả
t c
ờ ả ủ
ỉ ộ ờ ả
S m r ng là tìm không ch m t l
ữ
i c a bài toán đã cho.
nh ng l
i gi
ấ
c tìm th y
ng pháp
ạ
ộ ờ ả ượ
i gi
ứ
i, ta ti p t c xét ng viên k trong quá trình
ươ
ộ
i đ
: M t khi m t l
Ph
ế ụ
ế
và ghi l
ộ
ọ ứ
ch n ng viên m t cách có h th ng
ệ ố .
ượ
ẫ
c d n xu t t
ấ ừ (6.3.4) và
ượ
ư
ẫ ổ
Khuôn m u t ng quát đ
đ
:
c trình bày nh sau
22
23
procedure try(i: integer);
var k: integer;
begin
for k:=1 to m do
begin
select kth candidate;
if acceptable then
begin
record it;
if i
ả
ể ơ
ở ộ
ủ
ề
ậ
ả
Trong gi
i thu t m r ng, đ đ n gi n hóa đi u ki n d ng c a quá trình
ọ
ượ
ế ằ
ch n, phát bi u
ể repeat đ
c thay th b ng phát bi u
ệ ừ
ể for
program eightqueens(output);
var i: integer;
a: array [1.. 8] of boolean;
b: array [2.. 16] of boolean;
c: array [–7.. 7] of boolean;
x: array [1.. 8] of integer;
procedure print;
var k : integer;
begin
for k : 1 to 8 do write(x[k]:4);
writeln
end {print};
procedure try (i:integer);
var j: integer;
begin
for j:=1 to 8 do
if a[j] (cid:0) b[i+j] (cid:0) c[ij] then
begin
x[i]:=j;
a[j]:=false; b[i+j]:= false;
c[ij]:=false;
if i < 8 then try(i+1) else print;
a[j]:=true; b[i+j]:= true;
c[ij]:= true;
end
end {try};
24
begin
for i:= 1 to 8 do a[i]:=true;
for i:= 2 to 16 do b[i]:=true;
for i:= –7 to 7 do c[i]:=true;
try(1);
end.
ậ
ể ả
ấ ả
ờ
t c 92 l
i
ậ
ở ộ
ả
i thu t m r ng có th s n sinh t
Gi
ả
i cho bài toán 8 con h u.
gi
ậ
ỉ
ậ ự
ệ
ờ ả
i gi
i th t s khác bi
t
ư
Nh ng th t ra ch có 12 l
nhau.
25
N
x6
x2
ườ
ả
x7 ờ ả
i gi
x3 ượ ệ
c li
x5 i đó đ
x4 t kê trong b ng sau:
x8
876
264
200
136
504
400
72
280
240
264
160
336
6
3
6
8
8
1
4
7
3
6
8
1
8
8
4
5
6
7
7
1
8
3
5
6
7
4
2
4
1
8
8
8
4
5
4
5
2
2
5
6
7
6
6
3
7
1
6
7
5
6
7
7
4
5
5
6
6
7
7
8
3
7
8
2
3
3
1
4
1
8
1
3
4
5
3
3
5
4
3
5
5
4
3
4
M i hai l
x1
=========================================================
1
1
1
1
2
2
2
2
2
2
2
2
ữ ỉ ố ầ ử ể
c t N ch s l n th đ tìm m t ô an toàn.
26
ử ị ở ộ
Nh ng giá tr
ầ
Trung bình c n 161 phép th trong 92 l ộ
i này. ờ ả
i gi
Cây không gian trạng thái
Để tiện diễn tả giải thuật quay lui, ta xây dựng cấu trúc
Nút rễ của cây diễn tả trạng thái đầu tiên trước khi quá
cây ghi những lựa chọn đã được thực hiện. Cấu trúc cây
này được gọi là cây không gian trạng thái (state space
tree) hay cây tìm kiếm (search tree).
Các nút ở mức đầu tiên trong cây diễn tả những lựa
trình tìm kiếm lời giải bắt đầu.
27
chọn được làm ứng với thành phần đầu tiên của lời giải.
Các nút ở mức thứ haì trong cây diễn tả những lựa chọn
được làm ứng với thành phần thứ hai của lời giải và các
mức kế tiếp tương tự như thế.
Một nút trên cây KGTT được gọi là triển vọng nếu nó
tương ứng với lời giải bộ phận mà sẽ có thể dẫn đến lời
giải đầy đủ; trái lại, nó được gọi là một lời giải không
triển vọng.
Các nút lá diễn tả những trường hợp bế tắc (dead end) hay
những lời giải đầy đủ.
Thí dụ: Cho một bài toán như sau:
Tập biến: X, Y, Z.
Gán trị từ tập {1,2} vào các biến sao cho thỏa mãn các
ràng buộc: X = Y, X ≠ Z, Y > Z.
Hãy giải bài toán bằng một giải thuật quay lui.
Cây không gian trạng thái của bài toán này được cho ở
28
hình vẽ sau:
X =1
X =2
Y = 1
Y=2
Y = 1
Y=2
Z =1
(cid:0) (cid:0)
Z =2
Z=2
Z=1
(cid:0) (cid:0) (cid:0)
lời giải
ụ ề
ạ
Hình 6.9 Thí d v cây Không Gian Tr ng Thái
29
Độ phức tạp của giải thuật quay lui
ủ
ả
ậ
i thu t quay lui
ờ
ườ
Th i gian tính toán c a các gi
th
hàm mũ (exponential).
ng là
ế
ỗ
ờ ả
i gi
ạ
i đi l
ố
N u m i nút trên cây không gian tr ng thái có trung
bình (cid:0) nút con, và chi u dài c a l
ề
ủ ố
i là N,
ẽ ỉ ệ ớ (cid:0) N.
s t l
thì s nút trên cây
v i
ờ
ươ
ủ
ng
ậ ệ
i thu t đ quy t
ạ
ả
ớ ố
ng v i s nút trên cây không gian tr ng thái nên có
ộ ứ ạ
Th i gian tính toán c a gi
ứ
đ ph c t p hàm mũ.
30
ậ
ậ
i thu t nhánh và c n (branchand
ng gia du hành (TSP)
ườ ươ
i th
ả ỗ ặ ố
ộ ậ
: cho m t t p các
ố
ổ ố t c m i thành ph sao cho t ng
trình đi qua t
ủ ộ ỏ ơ
ả
Gi
bound)
Bài toán ng
thành ph và kho ng cách gi a m i c p thành ph , tìm
ộ ộ
m t l
ả
kho ng cách c a l
ữ
ấ ả ọ
trình nh h n M.
ẫ ộ ồ ị
ề
ướ ộ
ộ
ế
Đi u này d n đ n m t bài toán khác: cho m t đ th vô
ằ
ể ố ấ ả
t c các nút b ng m t chu
h
ng, có cách nào đ n i t
ơ
bài toán Chu trình
trình đ n hay không. Đây chính là
Hamilton (HCP).
ể ả i bài toán (HCP), ta có th c i biên gi
ướ ậ
ả
i thu t tìm
ể
ậ
i thu t này có th
31
ể ả
c (DFS) đ gi
ọ ỉ ơ ể ả
Đ gi
ề
ế
ki m theo chi u sâu tr
ồ ị
ọ ố
i đi đ n mà đi qua m i đ nh trong đ th .
sinh ra m i l
ệ ượ ằ ể ự ử ạ c b ng cách s a l ủ ụ
i th t c
Tìm kiếm vét cạn: Giải thuật DFS cải biên sinh ra mọi lối đi
đơn
ề
Đi u này có th th c hi n đ
ư
visit nh sau:
ọ ố ơ ừ i đi đ n t
ở ầ
ể
ủ ụ ệ
Th t c đ quy này có th
sinh ra m i l
ộ ỉ
m t đ nh kh i đ u nào đó.
Ví d :ụ
id :=0;
for k:= 1 to V do val[k]:=0;
visit(1);
procedure visit( k: integer);
var t: integer;
begin
id := id +1; val[k]:= id;
for t:= 1 to V do
if a[k, t] then
if val[k]= 0 then visit(t);
id := id –1; val[k] := 0
end;
32
Một thí dụ về bài toán TSP
A
2
H
I
1
6
3
1
B
C
G
1
2
4
1
2
1
K
J
D
E
4
3
2
1
2
1
F
M
L
Hình 5.10
33
ế
ạ
ố
ơ
Tìm ki m vét c n các l
i đi đ n
A
G
F
B
H
E
E
C
D
D
I
C
E
G
L
C
F
L
F
B
K
B
G
F
L
E
H
J
M
D
J
M
B
C
D
J
M
C
K
M
J
K
M
J
J
H
D
L
G
I
B
E
D
I
H
K
M
J
J
M
I
L
K
K
F
C
G
I
K
L
M
K
I
I
K
K
M
J
J
M
H
J
I
H
H
I
E M
L
J
K
H
I
I
K
K
M
J
L
M
G
H
C
F
E
H
I
J
L
M
G
H
H
I
G
K
K
M L
I
B
D
C
F
M L
G
H
L
M
G
J
H
I
D
B
B
D
H
F
C
D
B
M L
G
L
M
G
M L
G
F
C
Hình 5.11
34
Từ giải thuật sinh tất cả các lối đi đơn
đến giải thuật giải bài toán TSP
Ta có thể cải biên thủ tục visit ở trên để có thể nhận
diện chu trình Hamilton bằng cách cho nó kiểm tra
xem có tồn tại một cạnh nối từ đỉnh k về đỉnh 1 xuất
phát khi val[k]=V hay không.
Trong thí dụ trên, xem hình vẽ, ta tìm thấy 2 chu
Chương trình nhận diện chu trình Halmiton có thể
trình Hamilton là
A F D B C E L M J K I H G
A G H I K J M L E C B D F và hai chu trình này chỉ là một.
35
được sửa đổi để có thể giải bài toán TSP bằng cách
theo dõi chiều dài của lối đi hiện hành trong mảng val, và
theo dõi lối đi có chiều dài nhỏ nhất trong số các chu
trình Hamilton tìm thấy.
Ý tưởng nhánh và cận
ậ ả ả ụ ọ ố i đi
ể
i đi t
ơ
ọ i thu t DFS c i biên đ sinh ra m i l
ấ ổ
ố
ộ ố
t nh t (t ng
ộ ỹ ố ỏ ấ
ự ọ ế
Khi áp d ng gi
ế
đ n, trong quá trình tìm ki m m t l
ậ t a ỉ
tr ng s nh nh t) cho bài toán TSP, có m t k thu t
ấ
ế
nhánh quan tr ng là
k t thúc s tìm ki m ngay khi th y
ượ .
ể
ằ
r ng nó không th nào thành công đ
c
ượ
ư ầ ủ ấ
x đã đ
c tìm th y. Thì
i đi ch ađ yđ nào mà
ơ
ệ ế
ờ
ệ
ằ ọ ệ ự i đi đ n có chi phí
ố
ể
ớ ơ x. Đi u này có th
ề
l n h n
không g i đ quy th t c
36
ủ ụ visit
ủ
i đi ch ađ yđ hi n hành đã l n h n chi phí c a
ầ ủ ố ờ Gi
th t vô ích đ duy t ti p trên l
chi phí cho đ n hi n gi
ượ
đ
ế ố
n u l
ố
i đi đ y đ t
l t nh t ả ử ộ ố
s m t l
ể
ậ
ế
đã
ệ
c th c hi n b ng cách
ư ầ ủ ệ
ế
ấ cho đ n bây gi ớ ơ
.
Ý tưởng nhánh và cận (tt.)
ỏ ấ ố ế
b sótỏ
ế ượ ẽ
ộ i đi chi phí nh nh t nào n u
ư ậ Rõ ràng ta s không
ta bám sát m t chi n l l
c nh v y.
ủ c a các l
ỹ
ạ ả ư ầ ủ ể
i ch ađ yđ đ
ậ
ả
i thu t
gi ậ
c n (bound)
i gi ờ ả
i gi
ượ ọ
c g i là i ph i dò tìm đ
ậ
K thu t tính
ế ố ờ ả
h n ch s l
nhánh và c nậ .
ụ ể ượ ắ c g n vào
37
ả
Gi
các l ậ
i thu t này có th áp d ng khi có chi phí đ
i đi.ố
14
Bài toán 8 con hậu
ượ
ả c C.F. Gauss kh o sát năm 1850,
ư
ả
ế ượ
Bài toán này đã đ nh ng ông ta không hoàn toàn gi
i quy t đ
c.
ậ
ờ ậ ượ ặ “Tám con h u đ c đ t vào bàn c sao cho không ể ấ ậ có con h u nào có th t n công con h u nào
”.
ượ
hình 6.3.1, ta s có đ
ộ c m t
ủ ụ
ậ
ẽ ẫ ở Dùng khuôn m u th t c sau cho bài toán 8 con h u:
15
procedure try (i: integer); begin initialize selection of positions for ith queen; repeat make next selection; if safe then begin setqueen; if i < 8 then begin try (i + 1); if not successful then remove queen end end until successful (cid:0) no more positions end
16
ộ
ậ
ể ấ
ằ
ậ
Lu t c :
ộ ộ
ườ
ậ ờ M t con h u có th t n công các con h u khác n m trên ờ ng chéo trên bàn c .
ễ ữ ệ
ộ ể
cùng m t hàng, cùng m t c t hay là cùng đ Cách bi u di n d li u
var x: array[1..8] of integer; a: array[1..8] of Boolean;
b: array[b1..b2] of Boolean; c: array[c1..c2] of Boolean;
ể ễ ả ậ Làm cách nào đ di n t ờ 8 con h u trên bàn c ?
v iớ
ỉ ị ủ ộ ậ
x[i] ch v trí c a con h u trên c t th
ứ i;
ế a[j] cho bi ậ t không có con h u trên hàng th ứ j;
ế ậ ườ b[k] cho bi t không có con h u trên đ ng chéo th ứ k;
th ứ k.
17
ế ậ ườ c[k] cho bi t không có con h u trên đ ng chéo
ệ
ọ
ở
ấ ả
ẽ
t c các ô s có cùng giá tr c a
ộ ườ
ọ ộ i +j, và trên cùng m t đ
ượ c xác ả b và c ộ ườ ng ị ủ ng chép ị ủ
ấ ả
ẽ
t c các ô s có cùng giá tr c a
ệ
ị ố b1, b2, c1, c2 đ Vi c ch n tr cho các m c ỉ ố ủ ị đ nh b i cách mà các ch s c a các m ng ằ ượ c tính. Hãy chú ý r ng trên cùng m t đ đ chéo chi u ề t ổ t ng hai t a đ chi u ề diagonal, t hi u hai t a đ (
ọ ộ i – j ).
ượ
ư ậ
ế ư c tinh ch nh
ể setqueen đ
c ượ chi ti
ư ế
ề
ễ ả ư
ượ
nh sau:
c di n t
18
Nh v y, phát bi u sau: x[i]:=j; a[j]:=false; b[i+j]:=false;c[ij]:=false; Phát bi u ể removequeen đ : t hóa nh sau a[j] = true; b[i+j] = true ; c[ij] := true Đi u ki n ệ safe đ a[j] (cid:0) b[i+j] (cid:0) c[ij]
i : integer; q: boolean;
program eightqueeen1(output); {find one solution to eight queens problem} var a : array [1..8] of boolean; b : array [2..16] of boolean; c : array [–7..7] of boolean; x : array [1..8] of integer; procedure try(i: integer; var q: boolean); var j: integer; begin j:=0; repeat j:=j+1; q:=false; if a[j] (cid:0) b[i+j] (cid:0) c[ij] then
begin x[i]:=j; a[j]:=false; b[i+j]:=false; c[i-j]:=false; if i<8 then begin try (i+1, q); if (cid:0) q then begin a[j]:=true; b[i+j]:=true; c[i-j]:=true end end else q:=true end until q (cid:0) (j=8) end {try};
19
begin for i:= 1 to 8 do a[i]:=true; for i:= 2 to 16 do b[i]:=true; for i:= –7 to 7 do c[i]:=true; try (1,q); if q then for i:=1 to 8 do write (x[i]:4); writeln end
ậ ượ ở ộ ờ ả ủ i gi i c a bài toán 8 con h u đ c cho ẽ hình v
20
M t l sau:
H
1
H
2
H
3
H
4
H
5
H
6
H
7
H
8
21
Sự mở rộng: Tìm tất cả các lời giải
ự ở ộ
i gi
i mà t
ấ ả t c
ờ ả ủ
ỉ ộ ờ ả S m r ng là tìm không ch m t l ữ i c a bài toán đã cho. nh ng l
i gi
ấ
c tìm th y
ng pháp ạ
ộ ờ ả ượ i gi ứ
i, ta ti p t c xét ng viên k trong quá trình
ươ ộ i đ : M t khi m t l Ph ế ụ ế và ghi l ộ ọ ứ ch n ng viên m t cách có h th ng
ệ ố .
ượ
ẫ
c d n xu t t
ấ ừ (6.3.4) và
ượ
ư
ẫ ổ Khuôn m u t ng quát đ đ :
c trình bày nh sau
22
23
procedure try(i: integer);
var k: integer;
begin
for k:=1 to m do
begin
select kth candidate;
if acceptable then
begin
record it;
if i ả ể ơ ở ộ ủ ề ậ ả Trong gi i thu t m r ng, đ đ n gi n hóa đi u ki n d ng c a quá trình ọ ượ ế ằ ch n, phát bi u ể repeat đ c thay th b ng phát bi u ệ ừ
ể for program eightqueens(output);
var i: integer;
a: array [1.. 8] of boolean;
b: array [2.. 16] of boolean;
c: array [–7.. 7] of boolean;
x: array [1.. 8] of integer;
procedure print;
var k : integer;
begin
for k : 1 to 8 do write(x[k]:4);
writeln
end {print}; procedure try (i:integer);
var j: integer;
begin
for j:=1 to 8 do
if a[j] (cid:0) b[i+j] (cid:0) c[ij] then
begin
x[i]:=j;
a[j]:=false; b[i+j]:= false;
c[ij]:=false;
if i < 8 then try(i+1) else print;
a[j]:=true; b[i+j]:= true;
c[ij]:= true;
end
end {try}; 24 begin
for i:= 1 to 8 do a[i]:=true;
for i:= 2 to 16 do b[i]:=true;
for i:= –7 to 7 do c[i]:=true;
try(1);
end. t c 92 l i i th t s khác bi t 25 N x6 x2 ườ ả
x7 ờ ả
i gi
x3 ượ ệ
c li
x5 i đó đ
x4 t kê trong b ng sau:
x8 876
264
200
136
504
400
72
280
240
264
160
336 6
3
6
8
8
1
4
7
3
6
8
1 8
8
4
5
6
7
7
1
8
3
5
6 7
4
2
4
1
8
8
8
4
5
4
5 2
2
5
6
7
6
6
3
7
1
6
7 5
6
7
7
4
5
5
6
6
7
7
8 3
7
8
2
3
3
1
4
1
8
1
3 4
5
3
3
5
4
3
5
5
4
3
4 M i hai l
x1
=========================================================
1
1
1
1
2
2
2
2
2
2
2
2 ữ ỉ ố ầ ử ể
c t N ch s l n th đ tìm m t ô an toàn. 26 ử ị ở ộ
Nh ng giá tr
ầ
Trung bình c n 161 phép th trong 92 l ộ
i này. ờ ả
i gi Cây không gian trạng thái Để tiện diễn tả giải thuật quay lui, ta xây dựng cấu trúc Nút rễ của cây diễn tả trạng thái đầu tiên trước khi quá cây ghi những lựa chọn đã được thực hiện. Cấu trúc cây
này được gọi là cây không gian trạng thái (state space
tree) hay cây tìm kiếm (search tree). Các nút ở mức đầu tiên trong cây diễn tả những lựa trình tìm kiếm lời giải bắt đầu. 27 chọn được làm ứng với thành phần đầu tiên của lời giải.
Các nút ở mức thứ haì trong cây diễn tả những lựa chọn
được làm ứng với thành phần thứ hai của lời giải và các
mức kế tiếp tương tự như thế. Một nút trên cây KGTT được gọi là triển vọng nếu nó tương ứng với lời giải bộ phận mà sẽ có thể dẫn đến lời
giải đầy đủ; trái lại, nó được gọi là một lời giải không
triển vọng. Các nút lá diễn tả những trường hợp bế tắc (dead end) hay những lời giải đầy đủ. Thí dụ: Cho một bài toán như sau:
Tập biến: X, Y, Z.
Gán trị từ tập {1,2} vào các biến sao cho thỏa mãn các ràng buộc: X = Y, X ≠ Z, Y > Z. Hãy giải bài toán bằng một giải thuật quay lui.
Cây không gian trạng thái của bài toán này được cho ở 28 hình vẽ sau: (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) Hình 6.9 Thí d v cây Không Gian Tr ng Thái 29 i thu t quay lui Th i gian tính toán c a các gi
th hàm mũ (exponential). ng là ng 30 i thu t nhánh và c n (branchand ng gia du hành (TSP) ườ ươ
i th
ả ỗ ặ ố ộ ậ
: cho m t t p các
ố
ổ ố t c m i thành ph sao cho t ng trình đi qua t
ủ ộ ỏ ơ ữ
ấ ả ọ
trình nh h n M. ẫ ộ ồ ị ề
ướ ộ ộ
ế
Đi u này d n đ n m t bài toán khác: cho m t đ th vô
ằ
ể ố ấ ả
t c các nút b ng m t chu
h
ng, có cách nào đ n i t
ơ
bài toán Chu trình
trình đ n hay không. Đây chính là
Hamilton (HCP). ể ả i bài toán (HCP), ta có th c i biên gi ướ ậ
ả
i thu t tìm
ể
ậ
i thu t này có th 31 ể ả
c (DFS) đ gi
ọ ỉ ơ ể ả
Đ gi
ề
ế
ki m theo chi u sâu tr
ồ ị
ọ ố
i đi đ n mà đi qua m i đ nh trong đ th .
sinh ra m i l ệ ượ ằ ể ự ử ạ c b ng cách s a l ủ ụ
i th t c Tìm kiếm vét cạn: Giải thuật DFS cải biên sinh ra mọi lối đi
đơn
ề
Đi u này có th th c hi n đ
ư
visit nh sau: ọ ố ơ ừ i đi đ n t ở ầ ể
ủ ụ ệ
Th t c đ quy này có th
sinh ra m i l
ộ ỉ
m t đ nh kh i đ u nào đó.
Ví d :ụ
id :=0;
for k:= 1 to V do val[k]:=0;
visit(1); 32 A 2 H I 1 6 3 1 B C G 1 2 4 1 2 1 K J D E 4 3 2 1 2 1 F M L Hình 5.10 33 ế ạ ố ơ Tìm ki m vét c n các l i đi đ n A G F B H E E C D D I C E G L C F L F B K B G F L E H J M D J M B C D J M C K M J K M J J H D L G I B E D I H K M J J M I L K K F C G I K L M K I I K K M J J M H J I H H I E M L J K H I I K K M J L M G H C F E H I J L M G H H I G K K M L I B D C F M L G H L M G J H I D B B D H F C D B M L G L M G M L G F C Hình 5.11 34 Trong thí dụ trên, xem hình vẽ, ta tìm thấy 2 chu Chương trình nhận diện chu trình Halmiton có thể trình Hamilton là
A F D B C E L M J K I H G
A G H I K J M L E C B D F và hai chu trình này chỉ là một. 35 được sửa đổi để có thể giải bài toán TSP bằng cách
theo dõi chiều dài của lối đi hiện hành trong mảng val, và
theo dõi lối đi có chiều dài nhỏ nhất trong số các chu
trình Hamilton tìm thấy. ậ ả ả ụ ọ ố i đi ể
i đi t ơ
ọ i thu t DFS c i biên đ sinh ra m i l
ấ ổ
ố
ộ ố
t nh t (t ng
ộ ỹ ố ỏ ấ ự ọ ế Khi áp d ng gi
ế
đ n, trong quá trình tìm ki m m t l
ậ t a ỉ
tr ng s nh nh t) cho bài toán TSP, có m t k thu t
ấ
ế
nhánh quan tr ng là
k t thúc s tìm ki m ngay khi th y
ượ .
ể
ằ
r ng nó không th nào thành công đ
c ượ
ư ầ ủ ấ
x đã đ
c tìm th y. Thì
i đi ch ađ yđ nào mà ơ
ệ ế
ờ
ệ
ằ ọ ệ ự i đi đ n có chi phí
ố
ể
ớ ơ x. Đi u này có th
ề
l n h n
không g i đ quy th t c 36 ủ ụ visit
ủ
i đi ch ađ yđ hi n hành đã l n h n chi phí c a
ầ ủ ố ờ Gi
th t vô ích đ duy t ti p trên l
chi phí cho đ n hi n gi
ượ
đ
ế ố
n u l
ố
i đi đ y đ t
l t nh t ả ử ộ ố
s m t l
ể
ậ
ế
đã
ệ
c th c hi n b ng cách
ư ầ ủ ệ
ế
ấ cho đ n bây gi ớ ơ
. ỏ ấ ố ế b sótỏ
ế ượ ẽ
ộ i đi chi phí nh nh t nào n u
ư ậ Rõ ràng ta s không
ta bám sát m t chi n l l
c nh v y. ủ c a các l ỹ
ạ ả ư ầ ủ ể
i ch ađ yđ đ
ậ
ả
i thu t
gi ậ
c n (bound)
i gi ờ ả
i gi
ượ ọ
c g i là i ph i dò tìm đ ậ
K thu t tính
ế ố ờ ả
h n ch s l
nhánh và c nậ . ụ ể ượ ắ c g n vào 37 ả
Gi
các l ậ
i thu t này có th áp d ng khi có chi phí đ
i đi.ốậ
ể ả
ấ ả
ờ
ậ
ở ộ
ả
i thu t m r ng có th s n sinh t
Gi
ả
i cho bài toán 8 con h u.
gi
ậ
ỉ
ậ ự
ệ
ờ ả
i gi
ư
Nh ng th t ra ch có 12 l
nhau.
X =1
X =2
Y = 1
Y=2
Y = 1
Y=2
Z =1
Z =2
Z=2
Z=1
lời giải
ụ ề
ạ
Độ phức tạp của giải thuật quay lui
ủ
ả
ậ
ờ
ườ
ế
ỗ
ờ ả
i gi
ạ
i đi l
ố
N u m i nút trên cây không gian tr ng thái có trung
bình (cid:0) nút con, và chi u dài c a l
ề
ủ ố
i là N,
ẽ ỉ ệ ớ (cid:0) N.
s t l
thì s nút trên cây
v i
ờ
ươ
ủ
ậ ệ
i thu t đ quy t
ạ
ả
ớ ố
ng v i s nút trên cây không gian tr ng thái nên có
ộ ứ ạ
Th i gian tính toán c a gi
ứ
đ ph c t p hàm mũ.
ậ
ậ
ả
Gi
bound)
Bài toán ng
thành ph và kho ng cách gi a m i c p thành ph , tìm
ộ ộ
m t l
ả
kho ng cách c a l
procedure visit( k: integer);
var t: integer;
begin
id := id +1; val[k]:= id;
for t:= 1 to V do
if a[k, t] then
if val[k]= 0 then visit(t);
id := id –1; val[k] := 0
end;
Một thí dụ về bài toán TSP
Từ giải thuật sinh tất cả các lối đi đơn
đến giải thuật giải bài toán TSP
Ta có thể cải biên thủ tục visit ở trên để có thể nhận
diện chu trình Hamilton bằng cách cho nó kiểm tra
xem có tồn tại một cạnh nối từ đỉnh k về đỉnh 1 xuất
phát khi val[k]=V hay không.
Ý tưởng nhánh và cận
Ý tưởng nhánh và cận (tt.)

