Tải bản đầy đủ (.pdf) (134 trang)

KỸ THUẬT THIẾT KẾ THUẬT TOÁN - Le Minh Hoang ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.46 MB, 134 trang )



Chương I. KỸ THUẬT THIẾT KẾ THUẬT TOÁN

intelligent that survives. It is the one that is the most adaptable

Charles Darwin

i thiu mt s k thut quan trng trong vic tip cn bài toán và tìm
thut toán. Các lp thut toán s c tho lu      n
    tr (divide and conquer), Quy ho ng (dynamic
programming) và Tham lam (greedy).
Các bài toán trên thc th có muôn hình muôn v, không th t cách thc
 tìm gii thut cho m là nhng
n.
Khác vi nhng thut toán c th mà chúng m nh
   hc theo ki 
 tìm thy các thut toán này trong bt c n lp trình nào.
Chúng ta ch có th kho sát mt vài bài toán c th và hp cn
v, cách thit k gii thut. T n k t khi gii các bài
toán thc t.



Bài 1. Liệt kê
Có mt s bài toán trên thc t yêu cu ch rõ: trong mt tc có bao
ng tho mãn nhu kin nhng nào. Bài toán
này gi là bài toán lit kê hay bài toán duyt.
Nu ta biu ding ci dng mt cu hình các bin s  gii bài
toán lit kê, cn phc mt thut toán  có th t xây dc
tt c các cn ph


c hai yêu c
 c lp li mt cu hình
 c b sót mt cu hình
c khi nói v các thut toán lit kê, chúng ta gii thiu mt s khái nin:
1.1. Vài khái niệm cơ bản
1.1.1. Thứ tự từ điển
Nhc li rng quan h th t toàn ph c bt tp hp ,
là quan h hai ngôi tho mãn bn tính cht:
Vi 
 Tính ph bin (Universality): Hoc là  , hoc ;
 Tính phn x (Reflexivity):  
 Tính phi xng (Antisymmetry) : Nu  và  thì bt buc 
 Tính bc cu (Transitivity): Nu có   và  thì .
Các quan h  có th t suy ra t quan h  này.
Trên các dãy hu hnh mt quan h th t:
Xét 

và 

 dài , trên các phn t ca  và   th t toàn
ph



n:
 Hoc hai dãy ging nhau: 



 

 Hoc tn ti mt s   



và 




Th t i là th t t n (lexicographic order)  dài .
Khi hai dãy  và  có s phn t c th t t n.
Bng cách thêm vào cui dãy  hoc dãy  nhng phn t c bit gi là    dài ca  và
 bng nhau, và coi nhng phn t  này nh t c các phn t khác, ta l xác
nh th t t n c dài.
Ví d:




















Th t t t quan h th t toàn phn trên các dãy.
1.1.2. Chỉnh hợp, tổ hợp, hoán vị.
Cho  là mt tp hu hn gm  phn t và  là mt s t nhiên. Gi  là tp các s nguyên
 1 ti : 
 Chỉnh hợp lặp
Mt ánh x    ng mi phn t  mt và ch mt phn t 



,
c gi là mt chnh hp lp chp  ca 
Do  là tp hu hn ( phn t) nên ánh x  có th  nh qua bng các giá tr















, vì vy ta có th ng nht  vi dãy giá tr














và coi
dãy giá tr t chnh hp lp chp  ca .
Ví d  . Mt ánh x  cho bi:


1
2
3





ng vi tp nh




là mt chnh hp lp ca 
S chnh hp lp chp  ca tp  phn t là 


 Chỉnh hợp không lặp
M c gi là mt chnh hp không lp chp  ca . Nói cách khác, mt
chnh hp không lp là mt chnh hp lp có các phn t t.
Ví d mt chnh hp không lp chp 3



ca tp 

1
2
3





Số chỉnh hợp không lặp chập  của tập  phần tử là 









 Hoán vị
Khi  mi song ánh  c gi là mt hoán v ca . Nói cách khác mt hoán v
ca  là mt chnh hp không lp chp  ca .
Ví d:



là mt hoán v ca 

1
2
3
4
5
6










S hoán v ca tp  phn t là 

 





 Tổ hợp
Mi tp con gm  phn t ca  c gi là mt t hp chp  ca .
Ly mt t hp chp  ca , xét tt c  hoán v ca nó, mi hoán v s là mt chnh hp
không lp chp  ca . c là khi lit kê tt c các chnh hp không lp chp  thì
mi t hp chp  s c tính  ly nu xét v mt s ng:
S t hp chp  ca tp  phn t là 














Ta có công thc khai trin nh thc:

 


 










Vì vy s 


 c gi là h s nh thc (binomial coefficient) th , bc 
1.2. Phương pháp sinh
 áp d gii bài toán lit kê nu kin sau tho
mãn:
 Có th c mt th t trên tp các cu hình t hp cn lit kê. T 
bic cu tiên và cu hình cui cùng theo th t 
 Xây dc thut toán t mt cu hìni cu hình cuc cu
hình k tip nó.
1.2.1. Mô hình sinh
 vit bng mô hình chung:

«Xây dựng cấu hình đầu tiên»;
repeat
«Đưa ra cấu hình đang có»;
«Từ cấu hình đang có sinh ra cấu hình kế tiếp nếu còn»;
until «hết cấu hình»;

1.2.2. Liệt kê các dãy nhị phân độ dài 

Mt dãy nh  dài  là mt dãy 







 .
Có th nhn thy rng mt dãy nh phân 

là biu din nh phân ca mt giá tr nguyên
 

 






. S các dãy nh  dài  bng 

, th t t n trên các
dãy nh  dài  i quan h th t trên các giá tr s mà chúng biu
din. Vì vy, lit kê các dãy nh phân theo th t t i ch ra lt các dãy
nh phân biu din các s nguyên theo th t 

 .



Ví d vi , có 8 dãy nh  c lit kê:

000
001
010
011
100
101
110
111

0
1
2
3
4
5
6
7

Theo th t liu tiên là 




và dãy cui cùng là 





. Nu ta có mt dãy
nh  dài , ta có th sinh ra dãy nh phân k tip bng cách c
s 2 có nh) vào dãy hin ti.

10101111
+ 1
────────
10110000

Da vào tính cht ca phép cng hai s nh phân, cu hình k tip có th sinh t cu hình
hin ti bng cách: xét t cu  lên), tìm s 0 gu

 Nu thy thì thay s ng s t tt c các phn t phía sau v ng 0.
 Nu không thy thì thì toàn dãy là s u hình cui cùng.
Input
S .
Output
Các dãy nh  dài .
Sample

Input

Sample Output
3
000
001
010
011
100

101
110
111

 BINARYSTRINGS_GEN.PAS  
{$MODE OBJFPC}
program BinaryStringEnumeration;
var
x: AnsiString;
n, i: Integer;
begin
ReadLn(n);
SetLength(x, n);
FillChar(x[1], n, '0');
//Cu x=00 0



repeat
WriteLn(x);

//Tìm s u tiên t cui dãy
i := n;
while (i > 0) and (x[i] = '1') do Dec(i);
if i > 0 then


begin
x[i] := '1';



if i < n then


FillChar(x[i + 1], n - i, '0');
end
else
Break;


until False;
end.
1.2.3. Liệt kê các tập con có  phần tử
Ta s lt kê các tp con  phn t ca tp  theo th t t

Ví d:   , có 10 tp con:
{1, 2, 3} {1, 2, 4} {1, 2, 5} {1, 3, 4} {1, 3, 5}
{1, 4, 5} {2, 3, 4} {2, 3, 5} {2, 4, 5} {3, 4, 5}
Bài toán lit kê các tp con  phn t ca tp  có th quy v bài toán lit kê các
dãy  phn t 

 



 

. Nu sp xp các dãy này theo th
t t n, ta nhn thy:
Tu tiên (cu hình khi to) là .

u hình kt thúc) là       .
 










, ta có nhn xét rng gii hn
trên (giá tr ln nht có th nhn) ca 

là n, ca 

là  , ca 

là  ng
quát: gii hn trên ca 

   .
Còn tt nhiên, gii ha 



 .
 


 St c các phn t trong x t ti
gii hx  u không thì ta phi sinh ra mt dãy mn
tho  lk phn t nào chen
gia chúng khi sp th t t n.
Ví d: . C. Các phn t 

t ti gii
h sinh cu hình mi ta không th sinh bt phn t trong
s 

c, ta ph

 

c cu
hình mi 



. Cu hình này l mãn
tính cht v ln. Mu   


bng các gii hi cc là:




 







 




 




 
c cu hình mi 



là cu hình k ti 
li nhn thy rng 

 t gii hy ch c


 




.
Thu tip t

có th xây d
Tìm t cuu cho ti khi gp mt phn t 

t gii hn trên    
 Nu tìm thy:
 

lên 1
 t tt c các phn t 

bng gii h  
 Nu không tìm thy tc là mi phn t t gii hu hình cui cùng
Input
Hai s 




Output
Các tp con k phn t ca tp




Sample Input
Sample Output
5 3

{1, 2, 3}
{1, 2, 4}
{1, 2, 5}
{1, 3, 4}
{1, 3, 5}
{1, 4, 5}
{2, 3, 4}
{2, 3, 5}
{2, 4, 5}
{3, 4, 5}

 SUBSETS_GEN.PAS  Thut toán sinh lit kê các tp con  
{$MODE OBJFPC}
program SubSetEnumeration;
const
max = 100;
var
x: array[1 max] of Integer;
n, k, i, j: Integer;
begin
ReadLn(n, k);
for i := 1 to k do x[i] := i;


repeat


Write('{');
for i := 1 to k do
begin



Write(x[i]);
if i < k then Write(', ');
end;
WriteLn('}');

 k + i
i := k;
while (i > 0) and (x[i] = n - k + i) do Dec(i);
if i > 0 then


begin
Inc(x[i]);




for j := i + 1 to k do x[j] := x[j - 1] + 1;
end
else Break;
until False;
end.
1.2.4. Liệt kê các hoán vị
Ta s lt kê các hoán v ca tp 



theo th t t n.

Ví d vi n = 3, có 6 hoán v:









Mi hoán v ca tp 



có th biu dii dng mt mt dãy s 

. Theo
th t t n, ta nhn thy:
Hoán v u tiên cn lit kê:




Hoán v cui cùng cn lit kê:

  


Bu t hoán v




, ta s sinh ra các hoán v còn li theo quy tc: Hoán v s sinh
ra phi là hoán v v l hin t có mt hoán v nào
khác chen gia chúng khi sp th t.
Gi s hoán v hin ti là 



, xét 4 phn t cui cùng, ta thc
xp gim d 4 phn t này th 
c mt hoán v  hin ty ta phn 

 và thay nó
bng mt giá tr khác. Ta s thay bng giá tr nào?, không th là 1 bi nu vy s c
hoán v nh  

 ri (phn t c chn vào
nhng giá tr mà phn t n). Còn li các giá tr: 4, 5 và 6. Vì cn mt hoán v
v  l  n ti nên ta chn 

. Còn các giá tr 

s ly trong tp



 ln nên ta s tìm biu din nh nht ca 4 s này gán cho



tc là 





. Vy hoán v mi s là



.
Ta có nhn xét gì qua ví d này: n cui ca hoán v hin ti 

c xp gim dn, s


 là s nh nhn cui gim dn tho u kin l

. No
giá tr 

và 

thì ta s c hoán v



n cui 

vc sp xp

gim dn. Kn biu din nh nht cho các giá tr n cui thì ta ch co
n cui.


ng hp hoán v hin ti là



thì hoán v k tip s là 
th coi hoán v



n cui gim dn cui này ch gm 1 phn t (4)
Thut toán sinh hoán v k tip t hoán v hin ti có th xây d
n cui gim dn dài nht, tìm ch s  ca phn t 

ng lin cui
i vic tìm t v trí sát cuu, gp ch s  u tiên tha
mãn 



.
 Nu tìm thy ch s  
 n cui gim dn, tìm phn t 

nh nht v l

n

cui gim du này thc hin bng cách tìm t cuu gp ch s 
u tiên tho mãn 



(có th dùng tìm kim nh phân).
 o giá tr 

và 


 Lc th t n cui gim dn (

n cui tr n.
 Nu không tìm thy tp gim du hình cui cùng
Input
S nguy
Output
Các hoán v ca dãy




Sample Input
Sample Output
3

(1, 2, 3)
(1, 3, 2)
(2, 1, 3)

(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

 PERMUTATIONS_GEN.PAS  
{$MODE OBJFPC}
program PermutationEnumeration;
const
max = 100;
var
x: array[1 max] of Integer;
n, i, k, l, h: Integer;

//Th to giá tr hai tham bin x, y
procedure Swap(var x, y: Integer);
var
temp: Integer;
begin
temp := x; x := y; y := temp;
end;

begin
ReadLn(n);


for i := 1 to n do x[i] := i;
repeat

//In cu hình hin ti
Write('(');

for i := 1 to n do
begin
Write(x[i]);
if i < n then Write(', ');
end;
WriteLn(')');

//Sinh cu hình k tip

//Tìm i là ch s n cui gim dn
i := n - 1;
while (i > 0) and (x[i] > x[i + 1]) do Dec(i);
if i > 0 then
//Nu tìm thy

begin

//Tìm t cui dãy phn t u tiên (x[k]) l
k := n;
while x[k] < x[i] do Dec(k);

o giá tr x[k] và x[i]
Swap(x[k], x[i]);

//Lc th t n cui gim dn cui tr n
l := i + 1; h := n;
while l < h do
begin
Swap(x[l], x[h]);
Inc(l);

Dec(h);
end;
end
else Break;
//C dãy là gim dn, ht cu hình

until False;
end.
m c c cu hình th  n
có cu hình th   tính ph dng trong nhng thut
toán duyt hn ch na, không phi c c,
không phi k thut sinh cu hình k tip cho mn (Sinh các chnh hp
không lp chp  theo th t t n chng hn). Ta sang mt chuyên mn mt
t kê có tính ph d gii các bài toán lit kê phc t
là: Thut toán quay lui (Back tracking).
1.3. Thuật toán quay lui
Thu gii bài toán lit kê các cu hình. Thut toán này làm vic theo
cách:
 Mi cc xây dng bng cách xây dng tng phn t
 Mi phn t c chn bng cách th tt c các kh 
Gi s cu hình cn lit kê có dng 

t toán quay lui s xét tt c các giá tr 


có th nhn, th cho 

nhn lt các giá tr i mi giá tr th gán cho 

, thut toán

s xét tt c các giá tr 

có th nhn, li th cho 

nhn lt các giá tr i mi giá


tr th gán cho 

li xét tip các kh n 

, c tip tc
 mt cu hình thì lit kê ngay c
Có th mô t thut toán quay lui theo cách quy np: Thut toán s lit kê các cu hình 
phn t dng 

bng cách th cho 

nhn lt các giá tr có th. Vi mi giá tr th
gán cho 

, thut toán tip tc lit kê toàn b các cu hình    phn t 


1.3.1. Mô hình quay lui

//Th tc này th cho x[i] nhn lt các giá tr mà nó có th nhn
procedure Attempt(i);
begin
for «mọi giá trị v có thể gán cho x[i]» do

begin
«Thử cho x[i] := v»;
if «x[i] là phần tử cuối cùng trong cấu hình» then
«Thông báo cấu hình tìm được»
else
begin
«Ghi nhận việc cho x[i] nhận giá trị V (nếu cần)»;
Attempt(i + 1);
//G  chn tip x[i+1]

«Nếu cần, bỏ ghi nhận việc thử x[i] := V để thử giá trị khác»;
end;
end;
end;

Thut toán quay lui s bu bng li gi .
Tên gi thut toán quay lui là d duyt các cu hình: Mi khi th chn mt giá
tr cho 

, thut toán s g  tìm tip 

 y cho ti khi tin trình
duyt xét tìm ti phn t cui cùng ca ct tt c kh n


, tin trình s lùi li th t mt giá tr khác cho 

.
1.3.2. Liệt kê các dãy nhị phân
Biu din dãy nh  dài  i dng dãy 


. Ta s lit kê các dãy này bng cách th
dùng các giá tr



gán cho 

. Vi mi giá tr th gán cho 

li th các giá tr có th gán
cho 


t kê các dãy nh phân vnh khuôn d
trong mc 1.2.2.
 BINARYSTRINGS_BT.PAS  
{$MODE OBJFPC}
program BinaryStringEnumeration;
var
x: AnsiString;
n: Integer;

procedure Attempt(i: Integer);
//Th các cách chn x[i]

var


j: AnsiChar;

begin
for j := '0' to '1' do
//Xét các giá tr j có th gán cho x[i]

begin
//Vi mi giá tr 

x[i] := j;
//Th t x[i]

if i = n then WriteLn(x)
//Nu i = n thì in kt qu

else Attempt(i + 1);
//Ni phn t cui thì tìm tip x[i + 1]

end;
end;

begin
ReadLn(n);
SetLength(x, n);
Attempt(1);
//Khng thut toán quay lui

end.
Ví d: Khi , các li g quy thc hin thut toán quay lui có th v 
Hình 1-1.

Hình 1-1. Cây tìm kim quay lui trong bài toán lit kê dãy nh phân

1.3.3. Liệt kê các tập con có  phần tử
 lit kê các tp con  phn t ca tp  ta có th  lit kê các cu hình


,  





.
Theo các nhn xét  mc 1.2.3, giá tr ci và cn trên ca 

là:


 

  
(1.1)
(Gi thit rng có thêm mt s 

 khi xét công thc (1.1) vi )
Thut toán quay lui s xét tt c các cách chn 

t 1



 


n    , vi mi giá
tr p tt c các cách chn 

t 

  n     y khi chc
n 

thì ta có mt cu hình cn lit kê.
t kê các tp con  phn t bng thut toán quay lui vi khuôn
dnh trong mc 1.2.3.
Attempt(3)
000
x
3
:=0

x
3
:=1

Attempt(3)
x
3
:=0

x
3
:=1


Attempt(2)
x
2
:=0

x
2
:=1

Attempt(3)
x
3
:=0

x
3
:=1

Attempt(3)
x
3
:=0

x
3
:=1

Attempt(2)
x

2
:=0

x
2
:=1

Attempt(1)
x
1
:=0

x
1
:=1

001
010
011
000
001
010
011


 SUBSETS_BT.PAS  Thut toán quay lui lit kê các tp con  
{$MODE OBJFPC}
program SubSetEnumeration;
const
max = 100;

var
x: array[0 max] of Integer;
n, k: Integer;

procedure PrintResult;
//In ra tp con {x[1 k]}

var
i: Integer;
begin
Write('{');
for i := 1 to k do
begin
Write(x[i]);
if i < k then Write(', ');
end;
WriteLn('}');
end;

procedure Attempt(i: Integer);
//Th các cách chn giá tr cho x[i]

var
j: Integer;
begin
for j := x[i - 1] + 1 to n - k + i do
begin
x[i] := j;
if i = k then PrintResult
else Attempt(i + 1);

end;
end;

begin
ReadLn(n, k);
x[0] := 0;
Attempt(1);
//Khng thut toán quay lui

end.
V t thut toán quay lui ch khác nhau  th tc . Ví
d  t kê dãy nh phân, th tc này s th chn các giá tr 0 hoc 1 cho 

;
còn  t kê các tp con  phn t, th tc này s th chn 

là mt trong các
giá tr nguyên t ci 

  ti cn trên     thy tính ph
dng ca thut có th thích hp cho nhiu bài toán.  
pháp sinh tun t, vi mi bài toán li phi có mt thut toán sinh cu hình k ti
làm cho vit mi bài mt khác, bên ci thut toán sinh k tip nào
 c.


1.3.4. Liệt kê các chỉnh hợp không lặp chập 
 lit kê các chnh hp không lp chp  ca tp  ta có th  lit kê các
cu hình 


, các 

 t.
Th tc 



 xét tt c các kh n 

 s th ht các giá tr t n n 
b các phn t c 

chn. Mun xem các giá tr nàc chn ta s dng
k thut dùng mu:
 Khi to mt mng 



mang kiu logic boolean.  



cho bit giá tr 
có còn t  chn ru khi to tt c các phn t mng 




 t n n u t do.
 Tc chn các giá tr có th ca 


ta ch xét nhng giá tr  còn t do (




.
 c khi g quy 

 

 th chn tip 

t giá tr  va gán cho


 ch (



 các th tc 

 

, 

 


gi sau này không chn phi giá tr  a.

 Sau khi g quy 

 

p ti ta s th gán mt giá tr khác cho


thì ta s t giá tr  va th cho 

 



), bi khi 


nhn mt giá tr khác ri thì các phn t ng sau (

) hoàn toàn có th nhn li
giá tr  
 Tt nhiên ta ch cu/b u trong th tc 




, bi khi  thì tip theo ch có in kt qu ch không cn phi chn thêm phn
t nào na.
Input
Hai s 




.
Output
Các chnh hp không lp chp  ca tp




Sample Input
Sample Output
3 2
(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)

 ARRANGE_BT.PAS  
{$MODE OBJFPC}
program ArrangementEnumeration;
const
max = 100;
var


x: array[1 max] of Integer;
Free: array[1 max] of Boolean;
n, k: Integer;


procedure PrintResult;
//Th tc in cc

var
i: Integer;
begin
Write('(');
for i := 1 to k do
begin
Write(x[i]);
if i < k then Write(', ');
end;
WriteLn(')');
end;

procedure Attempt(i: Integer);
//Th các cách chn x[i]

var
j: Integer;
begin
for j := 1 to n do
if Free[j] then
//Ch xét nhng giá tr j còn t do

begin
x[i] := j;
if i = k then PrintResult
//Nn x[k] thì in kt qu


else
begin
Free[j] := False;
 chn

Attempt(i + 1);
//Attempt(i + 1) s ch xét nhng giá tr còn t do gán cho x[i+1]

Free[j] := True;
//B u, sp ti s th mt cách chn khác ca x[i]

end;
end;
end;

begin
ReadLn(n, k);
FillChar(Free[1], n, True);
Attempt(1);
//Khng thut toán quay lui

end.
Khi  t kê hoán v.
1.3.5. Liệt kê các cách phân tích số
Cho mt s , hãy tìm tt c các cách phân tích s  thành tng ca các s
 ca nhau ch tính là 1 cách và ch c lit kê
mt ln.
Ta s dùng thu lit kê các nghim, mi nghing vi mt dãy ,
 tránh s trùng lp khi lic: dãy  phi có th

t không gim: 




Thut bng th t quy 



: th các giá tr có th nhn
ca 

, mi khi th xong mt giá tr cho 

, th tc s g quy 

 

 th các


giá tr có th cho 

c mc th các giá tr cho 

 






là tng
ca tt c các phn t c 

: 

và th  giá min giá tr mà 

có th nhn.
Rõ ràng giá tr nh nht mà 

có th nhn chính là 

vì dãy  có th t không gim (Gi
s rng có thêm mt phn t 

, phn t này không tham gia vào vic lit kê cu hình
mà ch  hp thc hoá giá tr ci ca 

)
Nu 

i là phn t cui cùng, tc là s phi chn tip ít nht mt phn t 




na mà vic chn thêm 

không làm cho tt quá . Ta có:





 

 


 

 


  


(1.2)
Tc là nu 

i phn t cui cùng (cn g quy chn tip 

) thì giá tr ln nht 


có th nhn là





u 

là phn t cui cùng thì bt buc 

phi bng
  .
Vy thì th tc 



s g quy 

 

 tìm tip khi mà giá tr 

c
chn còn cho phép chn thêm mt phn t khác lc bng nó mà không làm tng
t quá : 






c li, th tc này s in kt qu ngay nu 

mang giá tr 
bng s thiu ht ca tng   phn t u so vi . Ví d n khi  thì th







là vin
tip 

c na.
Vi giá tr khi to  và 

, thut toán quay lui s c khng bng li gi




và hong theo cách sau:
 Vi mi giá tr : 






, th gán 

, cp nht  
quy tìm ti xong các giá tr có th cho 

, bin  c phc hi li

  c khi th gán mt giá tr khác cho 

.
 Cui cùng gán 

  và in kt qu ra dãy 

.
Input
S 
Output
Các cách phân tích s .


Sample Input
Sample Output
6

6 = 1+1+1+1+1+1
6 = 1+1+1+1+2
6 = 1+1+1+3
6 = 1+1+2+2
6 = 1+1+4
6 = 1+2+3
6 = 1+5
6 = 2+2+2
6 = 2+4
6 = 3+3
6 = 6
 NUMBERPARTITION_BT.PAS  L

{$MODE OBJFPC}
program NumberPartitioning;
const
max = 100;
var
x: array[0 max] of Integer;
n, m: Integer;

procedure Init;
//Khi to

begin
m := 0;
x[0] := 1;
end;

procedure PrintResult(k: Integer);
//In kt qu ra dãy x[1 k]

var
i: Integer;
begin
Write(n, ' = ');
for i := 1 to k - 1 do Write(x[i], '+');
WriteLn(x[k]);
end;

procedure Attempt(i: Integer);
//Thut toán quay lui


var
j: Integer;
begin
for j := x[i - 1] to (n - m) div 2 do
ng hp còn chn tip x[i+1]

begin
x[i] := j;
//Th t x[i]

m := m + j;
//Cp nht tng m

Attempt(i + 1);
//Chn tip

m := m - j;
//Phc hi tng m

end;
x[i] := n - m;
//Nu x[i] là phn t cui thì nó bt buc phi là n-m

PrintResult(i);
//In kt qu

end;

begin
ReadLn(n);

Init;


Attempt(1);
//Khng thut toán quay lui

end.
Bây gi ta xét tip mt ví d kinh n ca thu
1.3.6. Bài toán xếp hậu
Xét bàn c tc   . Mt quân hu trên bàn c có th c các quân
khác nm ti các ô cùng hàng, cùng ct hong chéo. Hãy tìm các xp  quân hu
trên bàn c sao cho không quân n mt cách xp vi  c ch ra
trong Hình 1-2.

Hình 1-2. Mt cách xp 8 quân hu lên bàn c   
N các hàng t trên xui theo th t t 1 ti , các ct t trái qua phi theo
th t t 1 ti t  quân hu lên bàn c, mi hàng phu (hu
c ngang), ta gi quân hu s t  hàng 1 là quân hu 1, quân hu  hàng 2 là quân
hu  hàng  là quân hu . Vy mt nghim ca bài toán s c bit khi ta
c v trí ct ca nhng quân hu.
ng bàn c   i), Bc (Trên). Mt
quân hu  ô



(hàng , ct ) s khng ch.
 Toàn b hàng 
 Toàn b ct 
 Toàn b các ô




th  ng thc   . Nhng ô này nm trên mt
c--TN).
 Toàn b các ô



th  ng thc   . Nhng ô này nm trên mt
-Tây B-TB)
T nhng nh ng chéo trên bàn c.
 Vi mi hng s . Tt c các ô



trên bàn c tha mãn   nm
trên m-TN, g-TN mang ch s 


 Vi mi hng s    . Tt c các ô



trên bàn c tha mãn  
nm trên m-TB, g-TB mang ch
s 


Hình 1-3. TN mang ch s TB mang ch s 0
Chúng ta s s dng ba m u:

 Mng 

. 

 nt  còn t do, 

 nt   mt quân
hu khng ch.
 Mng 

. 

 n-TN th  còn t do, 

 nu
 mt quân hu khng ch.
 Mng 

. 

 n-TB th  còn t do, 

 nu
 mt quân hu khng ch.
u c 3 mu mang giá tr u nào trên bàn c, các
cu t do)
Thut toán quay lui:
Xét tt c các ct, th t quân hu 1 vào mt ct, vi my, xét tt c các
t quân hu 2 không b quân hi th t và xét tit quân
hi khi n quân hu , ta in ra cách xp hu và d

 Khi chn v trí ct  cho quân hu th , ta phi chn ô



không b các quân ht
c là phi chn  tha mãn: ct  còn t do: 

-TN
ch s   còn t do: 

   -TB ch s   còn t do;


.
 Khi th c quân hu vào ô



, nu cui cùng () thì ta có
mt nghim. Nu không:















W
E
S
N
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8


 c khi g t quân hu th  u cng
chéo b quân hu vt khng ch: 






  các ln g
quy tip sau cht các quân hu k tip s không chn vào nhng ô b quân
hu vt khng ch.
 Sau khi g t quân hu th   sp ti ta li th
mt khác cho quân hu , ta b u cng chéo va b quân
hu va th t khng ch 





 tc là c
li thành t do, bt quân hu  sang v trí khác ri thì trên ct  và 2
 t mt quân hu khác
Hãy xem lt kê chnh hp không lp và hoán v v k thu
du.   khác vi lit kê hoán v là: lit kê hoán v ch cn mt mu xem giá
tr có t do không, còn bài toán xp hu thì cn phu c 3 thành phn: Cng
ng hu lit 
quân xe lên bàn c    t kê hoán
v.
Input
S 
Output
Mt các quân hu lên bàn c   
Sample Input
Sample Output
8

(1, 1)
(2, 5)
(3, 8)
(4, 6)
(5, 3)
(6, 7)
(7, 2)
(8, 4)

 NQUEENS_BT.PAS  
{$MODE OBJFPC}
program NQueens;
const
max = 100;
var
n: Integer;
x: array[1 max] of Integer;
a: array[1 max] of Boolean;
b: array[2 2 * max] of Boolean;
c: array[1 - max max - 1] of Boolean;
Found: Boolean;

procedure PrintResult;
//In kt qu mi khi tìm ra nghim



var
i: Integer;
begin

for i := 1 to n do WriteLn('(', i, ', ', x[i], ') ');
Found := True;
end;

//Kim tra ô (i, j) còn t  mt quân hu khng ch?
function IsFree(i, j: Integer): Boolean;
begin
Result := a[j] and b[i + j] and c[i - j];
end;

u / b u mt ô (i, j)
procedure SetFree(i, j: Integer; Enabled: Boolean);
begin
a[j] := Enabled;
b[i + j] := Enabled;
c[i - j] := Enabled;
end;

procedure Attempt(i: Integer);
//Th t quân hu i vào hàng i

var
j: Integer;
begin
for j := 1 to n do
//Xét tt c các ct

if IsFree(i, j) then
//Tìm v  khng ch


begin
x[i] := j;
//Th t vào ô (i, j)

if i = n then
begin
PrintResult;
n con hu n thì in ra 1 nghim

Exit;
end
else
begin
SetFree(i, j, False);
u

Attempt(i + 1);
//Th t quân hu th i + 1

if Found then Exit;
SetFree(i, j, True);
//B u

end;
end;
end;

begin
ReadLn(n);


u tt c các cng chéo là t do
FillChar(a[1], n, True);
FillChar(b[2], 2 * n - 1, True);
FillChar(c[1 - n], 2 * n - 1, True);
Found := False;
Attempt(1);
//Khng thut toán quay lui

end.

Thut toán dùng mt bin  làm c         u
, thut toán quay lui s trình tìm kim.


Mt sai lm d mc phi là ch t lnh dng thut toán quay lui trong phép th

if i = n then
begin
PrintResult;
Exit;
end;

Ny lnh Exit ch có tác dng trong th tc 



, mu mt
dây chuy  quy, cn phi thoát lin mt lot các th t  quy:







  

t lnh Exit vào sau li g quy chính là
t lnh Exit cho c mt dây chuy quy mi khi tìm ra nghim.
Mt s ng lp trình có lnh dng c  n 
chúng ta có th dùng lnh Halt thay cho lnh Exitu thut toán quay lui ch là mt
phc hin thut toán s còn phi làm nhiu vic khác na,
nh nu kin c c phép.
t dãy Exit là mt cách làm chính th  quy.
1.4. Kỹ thuật nhánh cận
Có mt lp t ra trong thc t yêu cu tìm ra mt nghim tho mãn mt s u
ki   tt nht theo mt ch tiêu c th p bài toán t 
(optimization). Nghiên cu li gii các lp bài toán tc v c quy hoch toán
hn phi nói rng trong nhing hp chúng ta ch xây dng
mt thut toán nào thc s hu hi gii bài toán, mà cho ti nay vic tìm nghim ca
chúng vn phi da trên mô hình lit kê toàn b các cu hình có th u
hình tt nht. Vicó tên gi là vét cn (exhaustive
search). Chính nh k thut này cùng vi s phát trin cn t mà nhiu bài
y li gii.
Vic lit kê cu hình có th t bt kê: Sinh tun t và tìm kim
quay lui.  tìm hiu k  ca thu gii thiu mt
n ch không gian duyt.
Mô hình thut toán quay lui là tìm kim trên mt cây phân cp. Nu gi thit rng mi nút
nhánh ca cây ch  cao  s có ti 

nút lá, con s này lt

nhiu ln so vc d liu vào . Chính vì vy mà na
trong vic chn 

thì s phi tr giá rt ln v chi phí thc thi thut toán bi quá trình tìm
kim lòng vòng vc chn k tip 

, 

t v t ra
là trong quá trình lit kê li gii ta cn tn dng nh loi b sm
nhc chn không phi t. K thui là k thu nhánh
cn (Branch-and-bound) trong tin trình quay lui.


1.4.1. Mô hình kỹ thuật nhánh cận
Da trên mô hình thut toán quay lui, ta xây dng mô hình sau:

procedure Init;
begin
«Khởi tạo một cấu hình bất kỳ best»;
end;

//Th tc này th chn cho x[i] tt c các giá tr nó có th nhn
procedure Attempt(i: Integer);
begin
for «Mọi giá trị v có thể gán cho x[i]» do
begin
«Thử đặt x[i] := v»;
if «Còn hi vọng tìm ra cấu hình tốt hơn best» then
if «x[i] là phần tử cuối cùng trong cấu hình» then

«Cập nhật best»
else
begin
«Ghi nhận việc thử x[i] := v nếu cần»;
Attempt(i + 1);
//G quy, chn tip x[i + 1]

«Bỏ ghi nhận việc đã thử cho x[i] := v (nếu cần)»;
end;
end;
end;

begin
Init;
Attempt(1);
«Thông báo cấu hình tối ưu best»;
end.

K thut nhánh cn thêm vào cho thut toán quay lui kh c, nu
tc th , giá tr th gán cho 

không có hi vng tìm thy cu hình tu hình
 thì th giá tr khác ngay mà không cn phi g quy tìm tip hay ghi nhn kt qu
na. Nghim ca bài toán s c làm tt dn, bi khi tìm ra mt cu hình mi t,
ta s cp nht  bng cu hình mi vc.
 kho sát mt vài k thun qua các bài toán c th.
1.4.2. Đồ thị con đầy đủ cực đại
 th  ci (Clique) là mt bài toán có rt nhiu ng dng trong
các mng xã hi, tin sinh hc, mng truyn thông, nghiên cu cu trúc phân t
phát biu bài toán mt cách hình th i và mi có quen bit mt s

i khác. Gi s quan h quen bit là quan h hai chiu, tc là ni  i 
i  i  c li. V là hãy chn ra mt tp gm nhii
nht trong s   i bt k c chn phi quen bit nhau.


t nhiu nghiên cu v i ta vc
thut toán v phc tc. Ta s trình bày mt cách gii bài toán Clique bng thut
toán quay lui kt hp vi k thut nhánh cn.
 Mô hình duyệt
Các quan h c biu din bi ma trn 







 nu
i  i  và 

 ni  i . Theo gi thit
ca bài toán, ma trn  là ma tri xng: 



().
Rõ ràng vi mi bt k thì có hai kh c chn hoi 
c chn. Vì vy mt nghim ca bài toán có th biu din bi dãy 









trong


 ni th  c chn và 

 ni th  c chn.
Gi  là s c chng vi dãy , tc là s v trí 

.
      bi mng 



, vi  là s  c chn
 ng vi dãy    n, ta khi to mng 



bi giá tr  và
 và bin  s c thay bng nht
t. Trên thc t có th khi to bng mt thut
toán g
Mô hình duyc thit k t kê các dãy nh phân bng thut toán quay lui:
Th hai giá tr True/False cho 


, vi mi giá tr va th cho 

li th hai giá tr ca 


Gi 



là s i quen ci  và 



là s i quen ci  
c chn. Giá tr 



nh ngay t u còn giá tr 



s c cp nht
ngay lp tc mi khi ta th quynh chn hay không chn mi  quen vi  ().
Mng 



và 




c s dng trong hàm c hn ch bt không gian
duyt.
 Hàm cận
Thuc thc hi quy thông qua th tc 



: Th hai giá tr có
th gán cho 

. Dây chuy   c b u t th tc 



và khi th tc




c gn trên tp nhi t 1 ti  
và s c chn trong tp này là .
Trong nhi t  ti , chc chn nu có chn thêm thì ta ch c phép chn nhng
i  mà 



 và 




 gii thích: 




i  không quen vi ít nht mn; còn 



 
là ni  c ch c chc chc không th có nhi 
i, không t hin có.
Nh  thit lp hàm cn: Khi th tc 



c gi, ta lc ra nhng
i trong phm vi t  ti  có 



 và 



 và lp gi thuyt rng



ng hp tt nht, tt c nhi này s c chn thêm. Gi thuyt này cho
   ng cn trên ca s  c ch   vào dãy các quy nh


  

u giá tr cn trên này vn , có th kt lun ngay rng
dãy quynh 

  

không th dn t cho dù ta
có th ht nhng kh ng có th ca 



. Th tc 



s không tin hành th
gán giá tr cho 

na mà thoát ngay, dây chuy quy lùi l i dãy quynh


  

.

Ngoài ra, th tc 



không nht thit phi th hai giá tr True/False gán cho 



.
N  



 hoc 



 thì ch cn th 



  , vì trong
ng hp này nu chi th  s b t vi nhng quynh chc hoc
không còn ti.
 Cài đặt
Ta s t bài toán Clique vi khuôn d
Input
 Dòng 1 cha s i  và s quan h quen bit  cách nhau ít nht mt du
cách
  dòng tip theo, mi dòng cha hai s nguyên  cách nhau ít nht mt du cách cho

bit v mt quan hi  quen nhau
Output
ng án chn ra nhii nh i bt k u quen nhau.

Sample Input
Sample Output

6 10
1 2
1 3
2 3
2 4
2 6
3 4
3 6
4 5
4 6
5 6
Number of guests: 4
Guests to be invited: 2, 3, 4, 6,


 CLIQUE_BB.PAS 
{$MODE OBJFPC}
program Clique;
const
maxN = 1000;
var
2
4

3
6
1
5

×