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.

ượ ô  ch a h  đ ô  đã đ ế c vi ng ạ ướ i b ứ ể c chuy n th

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 , có 8 kh  năng đ  ch n  ế ế ế  1 đ n 8  i. Chúng đ ô k  ti p  đ  đi t ư nh  sau:

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  ượ ọ ế ế ắ ”(dead­end). (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 i­th 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[i­j]:=false;  Phát bi u ể removequeen đ : t hóa nh  sau            a[j] = true; b[i+j] = true ;  c[i­j] := true  Đi u ki n ệ  safe đ            a[j] (cid:0)  b[i+j] (cid:0)  c[i­j]

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[i­j] 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 k­th 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[i­j] then          begin              x[i]:=j;              a[j]:=false; b[i+j]:= false;              c[i­j]:=false;              if i < 8 then try(i+1) else print;              a[j]:=true; b[i+j]:= true;              c[i­j]:= 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 (branch­and­

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.ố