Sunteți pe pagina 1din 8

CAP.

9 Metoda Backtracking (iterativă sau recursivă) if i<n then backtracking(i+1)


else afişează_soluŃia:
şterge_înregistrarea
end
9.1. Prezentare generală end
end;
Metoda se aplică problemelor în care soluŃia se poate reprezenta sub
forma unui vector x=(x1,x2,...xn) şi S=S1 x S2 x...x Sn, unde
mulŃimile Si sunt finite, S numindu-se spaŃiul soluŃiilor posibile. În
9.2 Probleme de generare. Oportunitatea utilizării metodei
particular, Si sunt identice având acelaşi număr M de elemente.
Pentru fiecare problemă concretă sunt date anumite relaŃii între backtracking
componentele vectorului x, numite condiŃii interne.
Pe acestă metodă se bazează rezolvarea unor probleme clasice ca:
Determinarea tuturor soluŃiilor rezultate se poate face
"opt regine", a "relaŃiilor stabile", colorarea unei hărŃi, tăierea unui
generând toate soluŃiile posibile şi verificând apoi care satisfac
fir de lungime l in părŃi de lungimi date, etc.
condiŃiile interne. Dar timpul de calcul ar fi foarte mare (dacă
mulŃimile Si ar avea numai câte 2 elemente, timpul ar fi O variantă a acestei metode este cea în care, pentru un xi ∈ vector
proporŃional cu 2n). soluŃie , xi+1 poate fi ales dintr-un număr M de posibilităŃi:
Metoda backtracking urmăreşte evitarea generării tuturor
soluŃiilor. Elementele vectorului x primesc valori pe rând, lui xi i se procedure back1(i:posibilitate);
begin
atribuie valori, doar dacă x1,x2,...,xi-1 au primit deja, valorile atribuite
if acceptabila then
trebuind să verifice condiŃiile de continuitate referitoare la x1, x2,...,
begin
xi. Doar apoi se trece la calculul lui xi+1. În cazul neîndeplinirii
condiŃiilor de continuitate, se alege următoarea valoare posibilă inregistreaza;
pentru xi, dacă Si a fost epuizat, se micşorează i, încercând o altă if solutie_incompleta then for k:=1 to M
do back1(posibilitate_k)
alegere pentru xi-1.
else tipareste_solutia;
sterge_inregistrarea
procedure backtracking(i:integer); {găseşte valoarea lui xi}
end
var posibilitate:integer; {pentru toate valorile}
end;
{posibile ale lui xi}
begin
Această variantă se foloseşte la rezolvarea problemelor:
for posibilitate:=1 to M do
begin "săritura calului", ieşirea dint-un labirint, etc. Se pretează atunci
if acceptabila then când pasul iniŃial este definit şi/sau numărul de paşi ai soluŃiei nu
begin este cunoscut.
înregistează_posibilitatea;

37
Problema celor 8 regine.
function posibil(x,y:integer):boolean; {returnează true dacă se poate
Program regine;{nerecursiv} pune regina la coord. (x,y)}
uses crt; begin
var r:array [1..8] of integer; {se memorează poziŃiile reginelor} posibil:=col[y] and dp[x-y] and ds[x+y] and(y<=8);
col:array [1..8] of boolean; {se memorează dacă o coloană e end;
liberă sau nu}
dp:array [-7..7] of boolean; {se memorează dacă o diagonală procedure initializare; {iniŃializează tablourile}
principală e ocupată sau nu} var i:integer;
ds:array [2..16] of boolean; {se memorează dacă o diagonală begin
secundară e ocupată sau nu} for i:=1 to 8 do col[i]:=true; {coloanele sunt libere}
nrr:integer; for i:=-7 to 7 do dp[i]:=true; {diagonalele principale sunt libere}
for i:=2 to 16 do ds[i]:=true; {diagonalele secundare sunt libere}
procedure afisare(x,y:integer); {afişează tabla şi reginele} nrr:=0;
var i,j:integer; end;
begin
textbackground(0); procedure ocupa(x,y:integer); {ocupă diagonalele şi coloana
clrscr; corespunzătoare}
nrr:=nrr+1; begin
for i:=1 to 8 do dp[x-y]:=false;{ocupă diagonala principală}
begin ds[x+y]:=false;{ocupă diagonala secundară}
for j:=1 to 8 do {se desenează pătrăŃelele} col[y]:=false;{ocupă colana}
begin end;
gotoxy(x+j,y+i);{poziŃionăm cursorul}
if (i+j) mod 2=0 then begin textbackground(blue);write(' ');end procedure elibereaza(x,y:integer); {eliberează diagonalele şi coloana
else begin textbackground(yellow);write(' corespunzătoare}
');end; begin
end; dp[x-y]:=true;{ocupă diagonala principală}
gotoxy(x+r[i],y+i); {se tipăreşte regină} ds[x+y]:=true;{ocupă diagonala secundară}
textbackground(red); col[y]:=true;{ocupă coloana}
write('R'); end;
end;
readln; procedure backtracking; {rezolvă problema utilizând bactracking
end; nerecursiv}

38
var i,j:integer; begin
begin initializare;{iniŃializăm tablourile}
i:=1; {i reprezintă nr liniei la care am ajuns} backtracking;
j:=1; {reprezintă coloana de pe care începem testarea} gotoxy(1,1);
while i>0 do write('Au fost găsite ',nrr,' soluŃii');
begin readln;
if posibil(i,j) then{dacă putem să punem regina} end.
begin
ocupa(i,j);{ocupăm diagonalele şi coloana} Generarea partiŃiilor unui număr.
r[i]:=j;{memorăm poziŃia}
if (i=8) then {dacă am ajuns la ultima linie} program generarea_partitiilor_unui_nr_natural;
begin var x:array[0..100] of integer;
afisare(10,10); {afişam rezultatul} n:integer;
elibereaza(i,j); {eliberăm diagonalele şi coloana} procedure scrie(k:integer);{afisează pe n ca sumă de k nr.}
j:=j+1;{şi trecem la poziŃia următoare} var i:integer;
end begin
else {dacă nu am ajuns la ultima linie} write('n=');
begin for i:=1 to k-1 do write(x[i],'+');
i:=i+1; {trecem la linia următoare} writeln(x[k]);
j:=1; {începem să testăm începând de la prima coloană} end;
end; {k=nr. de partişii;n=nr. ce se partiŃionează}
end procedure part(k,n:integer);
else j:=j+1; {dacă nu e posibil să punem regina pe poziŃia(i,j) var i:integer;
trecem la poziŃia următoare} begin
if j>8 then {dacă j>8, deci pe linia i nu mai putem pune nimic} for i:=1 to n do
begin if i>=x[k-1]then
i:=i-1; {ne întoarcem la linia anterioară} begin
j:=r[i]; {vedem pe ce poziŃie am pus regina} x[k]:=i;{partiŃia k poate lua orice val. pozitivă mai mică ca n}
elibereaza(i,j); {o luăm de acolo} if n-i>0 then part(k+1,n-i){dacă mai poate fi partiŃionat se
j:=j+1; {şi încercăm să o punem pe coloana imediat următoare} partiŃionează}
end; else
end; {de la while} scrie(k);{dacă nu, se afişează}
end; end;
end;

39
if x[i]>max then max:=x[i];{numărul de mulŃimi}
begin if k=n+1 then scrie(max){dacă nr. de elem. ce se va adăuga este
write('Dati n:');readln(n);x[0]:=0; n+1 se afişează}
part(1,n); else
readln; {vom încerca să adăugăm elementul k mulŃimii nr. a}
end. for a:=1 to max+1 do{deci îl vom adăuga mulŃimii 1, apoi la mult.
2 ...}
Generarea partiŃiilor unei mulŃimi. begin
x[k]:=a;{elementul k face parte din mulŃimea a}
program generarea_partitiilor_unei_multimi; partitioneaza(k+1);{se trece la următorul element}
{În x[i] se reŃine numărul mulŃimii din care face parte elementul i} end;
var x:array[1..100] of integer; end;
n:integer;{nr. de elemente} begin
procedure scrie(max:integer);{max reprezintă nr. de write('DaŃi n:');readln(n);
partiŃii(mulŃimi)} partitioneaza(1);
var i,j:integer; end.
begin
for i:=1 to max do{pentru fiecare mulŃime în parte}
begin Plata unei sume cu bancnote de valori diferite.
write('{');
for j:=1 to n do{tipărim elementul j} program plata_unei_sume_cu_bancnote;
if x[j]=i then write(j,' ');{dacă aparŃine mulŃimii i} uses crt;
writeln('}'); const nmax=20;
end; type nr_banc=array[1..nmax] of word;
readln; var b:array[1..nmax] of longint;{valorile bancnotelor}
end; nrb:nr_banc;{nr. de bancnote din fiecare valoare}
nb:integer;{nr. de bancnote}
procedure partitioneaza(k:integer);{k = nr. elementului ce se V:longint;{Suma care trebuie plătită}
adaugă} procedure citire;
var a,max,i:integer; var i:integer;
begin begin
max:=0;{vom căuta nr. maxim al mulŃimii la care a fost adăugat clrscr;
unul} write('DaŃi suma : ');readln(v);
for i:=1 to k-1 do{din primele k-1 elemente, acesta este practic} write('DaŃi nr. de bancnote:');readln(nb);

40
for i:=1 to nb do else afisare;{dacă am ajuns la suma dorită afişăm}
begin nrb[i]:=nrb[i]-1;{nr. de bancnote scade(punem bancnota la loc)}
write('DaŃi valoarea bancnotei ',i,' :');readln(b[i]); end;
nrb[i]:=0;{din bancnota i nu am luat niciuna pentru plata sumei} end;
end;
end; begin
procedure afisare; citire;
var j:integer; suma(0,1);{la început suma este zero, pornim de la prima bancnotă}
c:char; end.
f:boolean;
begin
clrscr; Labirint.
write('S=');
f:=false; Program Labirint;
for j:=1 to nb do uses crt;
if nrb[j]<>0 then var a:array[1..25,1..80] of char;{în a se memorează labirintul, care
if f then write('+',nrb[j],'*',b[j]) are dimensiunea ecranului}
else begin write(nrb[j],'*',b[j]);f:=true;end; Procedure citire;{se citeşte labirintul din fişier}
while not keypressed do; var f:text;
c:=readkey; i,j:integer;
if c= #27 then halt; begin
end; Assign(F,'labirint.txt');{asignăm identificatorul de fişier}
procedure suma(s:longint;x:integer);{s-este suma curentă, x-nr. reset(f);{deschidem fişierul pentru citire}
ultimei bancnote ce a fost adăugată } for i:=1 to 24 do begin
var i:integer; for j:=1 to 79 do read(f,a[i,j]);
begin readln(f);
for i:=x to nb do {pornim de la ultima bancnotă adăugată, pentru a end;
evita repetările} close(f);
if (s+b[i])<=v then {dacă prin adăugarea bancnotei i suma nu end;
creşte}
begin {peste valoarea la care trebuie să ajungem} Procedure afisare;{afişează labirintul pe ecran}
nrb[i]:=nrb[i]+1;{creştem nr de bancnote} var i,j:integer;
if (s+b[i])<v then suma(s+b[i],i){dacă suma actuală e mai mică begin
decât cea la care trebuie să ajungem } for i:=1 to 24 do begin

41
for j:=1 to 79 do begin Citire;{citeşte labirintul din fişier }
if a[i,j]='z' then a[i,j]:=' '; Afisare;{afişează labirintul pe ecran}
write(a[i,j]);end; TextColor(15);
writeln; back(22,14);{caută drumul spre ieşire pornind din punctul de
end; coordonate 22,14}
end; readln;
{procedura back încearcă să găsească drumul spre ieşire} TextColor(15);
Procedure back(x,y:integer); clrscr;
begin END.
if a[x,y]=' ' then begin{dacă la poziŃia curentă nu se află nimic Labirint – varianta 2
atunci} {Se dă un caroiaj dreptunghiular cu n linii şi m coloane. În fiecare
a[x,y]:='x';{marcăm că am fost pe acolo} celulă se află un număr din intervalul [0, 15], a cărui reprezentare
gotoxy(y,x);write('x');delay(50);{afişăm pe ecran} binară pe 4 poziŃii indică ieşirile spre celulele alăturate în ordinea N,
{testăm dacă am ajuns la margine, dacă da, aşteptăm apăsarea tastei E, S, V. Ieşirea într-o anumită direcŃie este posibilă dacă şi numai
<ENTER> } dacă bitul corespunzător acelei direcŃii este 1. Să se elaboreze un
if (x=1) or (y=1) or (x=24) or (y=79) then begin program care determină dacă dintr-o celulă oarecare a caroiajului se
readln; poate ieşi în afara lui.
exit; Dacă exista ieşire spre:
end N atunci bitul 4 (numărând de la dreapta)e 1
else begin {dacă nu am ajuns la margine atunci încercăm în E atunci bitul 3 e 1, deci valoarea de test e 4
continuare să ieşim din labirint} S atunci bitul 2 e 1, valoarea de test e 2
back(x,y-1);{încercă în sus} V atunci bitul 1 e 1, valoarea de test e 1
back(x+1,y);{încearcă în dreapta} Valoarea de test se calculează ca fiind 2 la puterea numărului bitului
back(x,y+1);{încearcă în jos} minus 1}
back(x-1,y);{încercă la stânga}
end; program caroiaj;
gotoxy (y,x); write (' '); delay(50); uses crt;
a[x,y]:=’ ‘;{şterge marcajul} var a:array[1..100,1..100] of byte;{se reŃine caroiajul}
end; n,m,nr:integer;
end; xp,yp:integer;
procedure citire;
BEGIN var i,j:integer;
TextColor(8); f:text;
clrscr;{şterge ecranul} begin

42
assign(f,'date.in'); if a[i,j]>15 then begin textbackground(red);write((a[i,j] and
reset(f); 15):2);end
readln(f,n,m); else begin textbackground(blue);write(a[i,j]:2);end;
for i:=1 to n do writeln;
begin end;
for j:=1 to m do repeat until keypressed;
read(f,a[i,j]); c:=readkey;
readln(f); if c= #27 then halt;
end; end;
close(f); {procedura caută drumul spre ieşire}
end; procedure cauta(x,y:integer);
{returnează true dacă în octetul x se specifică că este posibil să begin
mergem în directia (N, E, S, V)} if a[x,y]<16 then {dacă nu am fost pe acolo}
function pot(c:char;x:byte):boolean; begin
var f:boolean; a[x,y]:=a[x,y]+128;{marcăm casuŃa ca fiind vizitată}
begin if pot('N',a[x,y]) then {dacă putem merge spre nord}
case c of {vedem în ce direcŃie încercăm} if x=1 then afisare {dacă suntem la margine afişăm}
'N':f:=(x and 8)>0;{în sus} else cauta(x-1,y);{dacă nu mergem în sus}
'E':f:=(x and 4)>0;{la stânga} if pot('E',a[x,y]) then
'S':f:=(x and 2)>0;{în jos} if y=m then afisare
'V':f:=(x and 1)>0;{la dreapta} else cauta(x,y+1);
end; if pot('S',a[x,y]) then
pot:=f; if x=n then afisare
end; else cauta(x+1,y);
procedure afisare;{afişeaza drumul} if pot('V',a[x,y]) then
var i,j:integer; if y=1 then afisare
c:char; else cauta(x,y-1);
begin a[x,y]:=a[x,y]-128;{la revenire eliberăm drumul}
nr:=nr+1;{nr. de soluŃii creşte} end;
textbackground(black);textcolor(yellow); end;
clrscr; begin
for i:=1 to n do citire;
begin write('DaŃi coord. de pornire:'); readln(xp,yp);
for j:=1 to m do cauta(xp,yp);

43
writeln(‘Au fost afişate ‘,nr,’ soluŃii’); for i:=1 to n do begin {se parcurge tabla}
end. for j:=1 to n do begin
textbackground((i+j) mod 2);
write(a[i,j]:2);
Algoritmi de acoperire a tablei de şah prin săritura calului. end;
writeln;
program saritura_calului; end;
uses crt; while not keypressed do;
type coord=record c:=readkey;
x,y:integer; if c= #27 then halt;
end; end;
var a:array[1..100,1..100] of integer;{0-liber, nr- reprezintă a câta
poziŃie este} procedure back(x,y,k:integer);
p:array[1..8] of coord;{în p se memorează poziŃiile în care poate var i:integer;
sări calul} begin
n:integer; {n-dim. tablei } if (x>0)and(x<=n)and(y>0)and(y<=n)then {dacă este în interiorul
tablei}
procedure init; if a[x,y]=0 then {verificam daca căsuŃa e liberă}
begin {se pun în p poziŃiile în care poate sări calul} begin
p[1].x:=1;p[1].y:=-2; { _8_1_ } a[x,y]:=k; {marcăm, înregistrăm}
p[2].x:=2;p[2].y:=-1; { 7___2 } if k=n*n then afis {dacă sa parcurs toată tabla afişăm}
p[3].x:=2;p[3].y:=1; { __C__ } else {altfel încercăm rând pe rând cele 8 posibilităŃi}
p[4].x:=1;p[4].y:=2; { 6___3 } for i:=1 to 8 do
p[5].x:=-1;p[5].y:=2; { _5_4_ } back(x+p[i].x,y+p[i].y,k+1);
p[6].x:=-2;p[6].y:=1; a[x,y]:=0; {ştergem înregistrarea}
p[7].x:=-2;p[7].y:=-1; end;
p[8].x:=-1;p[8].y:=-2; end;
end;
begin
procedure afis;{afişează tabla} write('DaŃi dimensiunea tablei:');readln(n);
var i,j:integer; init;
c:char; back(1,1,1);{se porneşte din colŃul stânga sus (coord.[1,1])}
begin end.
clrscr;

44

S-ar putea să vă placă și