Sunteți pe pagina 1din 6

5.4.

Metoda reluării

În metoda reluării se presupune că soluţia problemei pe care trebuie să o rezol-


văm poate fi reprezentată printr-un vector:

X=(x1, x2 , ..., xk , ... , xn).

Fiecare componentă xk a vectorului X poate lua valori dintr-o anumită mulţime


Ak, k = 1, 2, ..., n. Se consideră că cele mk elemente ale fi ecărei mulţimi Ak
sînt ordonate
conform unui criteriu bine stabilit, de exemplu, în ordinea apariţiei lor în
memoria
calculatorului.

În principiu, astfel de probleme pot fi soluţionate prin metoda trierii, tratînd


vec-
torul X ca un element al produsului cartezian S = A1A2 ... An. Dezavantajul me-
todei trierii constă în faptul că timpul cerut de algoritmul respectiv este foarte
mare.

De exemplu, pentru mulţimile A1, A2, ..., An formate numai din cîte două elemente,
timpul necesar este O(2n

), deci exponenţial.

Pentru evitarea trierii tuturor elementelor produsului cartezian A1A2 ... An, în
metoda reluării componentele vectorului X primesc valori pe rînd, în sensul că lui
xk
i se atribuie o valoare numai dacă au fost deja atribuite valori lui x1, x2 , ...,
xk-1 . Mai
mult, odată o valoare pentru xk stabilită, nu se trece direct la atribuirea de
valori lui
xk+1, ci se verifi că anumite condiţii de continuare referitoare la x1, x2 , ...,
xk. Aceste

127
condiţii stabilesc situaţiile în care are sens să trecem la calculul lui xk+1. Dacă
aceste

condiţii nu sînt satisfăcute, va trebui să facem o altă alegere pentru xk sau, dacă
ele-
mentele din mulţimea Ak s-au epuizat, să micşorăm pe k cu o unitate încercînd să

facem o nouă alegere pentru xk-1.


Menţionăm faptul că anume micşorarea lui k dă nume metodei studiate, cuvîntul
„reluare” semnifi cînd revenirea la alte variante de alegere a variabilelor x1,
x2 , ..., xk-1.

Evident, aceeaşi semnifi caţie o are şi denumirea engleză a metodei în studiu 


back-
tracking (back  înapoi, track  urmă).

Pentru exemplifi care, în fi gura 5.4 este prezentată ordinea în care sînt
examinate

elementele mulţimilor A1 = {a11, a12}, A2 = {a21, a22} şi A3 = {a31, a32, a33}. În


scopuri di-
dactice se consideră că mulţimile A1 şi A2 au cîte două elemente (m1 = 2, m2 = 2),
iar
mulţimea A3  trei elemente (m3 = 3). Elementele akj ale mulţimilor respective sînt

simbolizate prin cerculeţe. Rezultatele verifi cării condiţiilor de continuare sînt


repre-
zentate prin valorile binare 0 (false) şi 1 (true).

A1

A2

A3

k:=1

k:=k+1
0
0
k:=k+1 k:=k–1
k:=k+1

Fig. 5.4. Căutarea soluţiei prin metoda reluării

Din fi gura 5.4 se observă că primul element a11 din mulţimea A1 nu satisface con-
diţiile de continuare şi, în consecinţă, se trece la elementul al doilea a12 din
aceeaşi

mulţime. Mai departe în vectorul X se include primul element a21 din mulţimea A2,
element care satisface condiţiile de continuare, şi se trece la examinarea
elementelor
din mulţimea A3.
Întrucît niciunul din elementele a31 , a32 , a33 nu satisface condiţiile de
continuare,
se revine la mulţimea A2 din care se alege elementul al doilea, şi anume, a22. După

aceasta se testează din nou elementele mulţimii A3, elementul a32 satisfăcînd
condiţi-
ile de continuare.

Schema generală a unui algoritm recursiv bazat pe metoda reluării este redată cu
ajutorul procedurii ce urmează:
procedure Reluare(k:integer);
begin
if k<=n then

128
begin
X[k]:=PrimulElement(k);
if Continuare(k) then Reluare(k+1);
while ExistaSuccesor(k) do
begin
X[k]:=Succesor(k);
if Continuare(k) then Reluare(k+1)
end; { while }
end { then }
else PrelucrareaSolutiei;
end; {Reluare}

Procedura Reluare comunică cu programul apelant şi subprogramele ape-


late prin variabilele globale ce reprezintă vectorul X şi mulţimile A1, A2, ...,
An.

Subprogramele apelate execută următoarele operaţii:


PrimulElement(k)  returnează primul element din mulţimea Ak;
Continuare(k)  returnează valoarea true dacă elementele înscrise în primele

k componente ale vectorului X satisfac condiţiile de continuare şi false în caz


con-
trar;

ExistaSuccesor(k)  returnează valoarea true dacă elementul memorat în


componenta xk are un succesor în mulţimea Ak şi false în caz contrar;
Succesor(k)  returnează succesorul elementului memorat în componenta xk;
PrelucrareaSolutiei  de obicei, în această procedură soluţia reţinută în
vectorul X este afişată la ecran.

Pentru o înţelegere mai clară a procesului recursiv, vom urmări execuţia procedu-
rii Reluare în cazul mulţimilor A1, A2, şi A3 din fi gura 5.3.

La execuţia apelului Reluare(1) în componenta x1 a vectorului X se înscrie pri-


mul element al mulţimii A1:

X=(a11).

Întrucît în cazul acestui vector apelul Continuare(1) returnează valoarea fal-


se, se trece la execuţia instrucţiunii while. Apelul ExistaSuccesor(1) returnea-
ză valoarea true şi, prin urmare, în componenta x1 a vectorului X se înscrie succe-
sorul elementului a11:

X=(a12).

De data aceasta apelul Continuare(1) returnează valoarea true şi, prin urma-
re, se trece la execuţia recursivă a apelului Reluare(2). Evident, în componenta x2

a vectorului X va fi înscris primul element din mulţimea A2:

X=(a12, a21).

Pentru acest vector funcţia Continuare returnează valoarea true, fapt ce de-
clanşează execuţia recursivă a apelului Reluare(3).

În cazul apelului Reluare(3) componenta x3 a vectorului X ia recursiv valorile


a31, a32 şi a33:

X=(a12, a21, a31);


X=(a12, a21, a32);

129

X=(a12, a21, a33),

însă nici unul din aceşti vectori nu satisface condiţiile de continuare. După
exami-
narea ultimului element din mulţimea A3, funcţia ExistaSuccesor returnează va-
loarea false şi, în consecinţă, se revine în contextul apelului Reluare(2). În
acest

context în componenta x2 a vectorului X se înscrie succesorul elementului a21:

X=(a12, a22).

Întrucît şi pentru acest vector funcţia Continuare returnează valoarea true,

din nou se execută apelul recursiv Reluare(3). Însă, spre deosebire de apelul pre-
cedent, în acest caz vectorul

X=(a12, a22, a32)

satisface condiţiile de continuare, fapt ce declanşează execuţia apelului recursiv


Reluare(4). În acest apel k>n şi, prin urmare, procedura PrelucrareaSolutiei
va afişa coordonatele vectorului X la ecran.
Exemplu. Se consideră mulţimile A1, A2, ..., An, fi ecare mulţime fi ind formată
din
mk numere naturale. Selectaţi din fi ecare mulţime cîte un număr în aşa mod încît
suma lor să fi e egală cu q.

Rezolvare. Vom reprezenta mulţimile A1, A2, ..., An prin liniile tabloului
bidimensi-
onal (matricei) A = ||akj||. Numărul de elemente mk al fi ecărei mulţimi Ak va fi
reţinut

în componenta respectivă a tabloului unidimensional (vectorului) M = ||mk||.


Din enunţul problemei rezultă că toate condiţiile de continuare sînt respectate
numai atunci cînd suma elementelor referite de primele k componente ale vectorului

X nu depăşeşte valoarea q pentru k<n şi este egală cu q pentru k = n. Pentru a


simpli-
fi ca scrierea programului, vom memora în vectorul X numai indicii j ai elementelor

aij selectate din mulţimile A1, A2, ..., An.


Program P154;
{ Program bazat pe metoda reluării }
const mmax=50; { numărul maximal de mulţimi }
nmax=50; { numărul maximal de elemente }
type Natural = 0..MaxInt;
Multime = array [1..nmax] of Natural;
var A : array[1..nmax] of Multime;
n : 1..nmax; { numărul de mulţimi }
M : array[1..nmax] of 1..mmax; { cardinalul mulţimii S[k] }
X : array[1..nmax] of 1..mmax; { indicii elementelor
selectate }

q : Natural;
k, j : integer;
Indicator : boolean;
function PrimulElement(k : integer) : Natural;
begin
PrimulElement:=1;
end; {PrimulElement }

130
function Continuare(k : integer) : boolean;
var j : integer;
suma : Natural;
begin
suma:=0;
for j:=1 to k do suma:=suma+A[j, X[j]];
if ((k<n) and (suma<q)) or ((k=n) and (suma=q))
then Continuare:=true
else Continuare:=false;
end; { Continuare }
function ExistaSuccesor(k : integer) : boolean;
begin
ExistaSuccesor:=(X[k]<M[k]);
end; { ExistaSuccesor }
function Succesor(k : integer) : integer;
begin
Succesor:=X[k]+1;
end; { Succesor }
procedure PrelucrareaSolutiei;
var k : integer;
begin
write(’Soluţia: ’);
for k:=1 to n do write(A[k, X[k]], ’ ’);
writeln;
Indicator:=true;
end; { PrelucrareaSolutiei }
procedure Reluare(k : integer);
{ Metoda reluarii - varianta recursiva }
begin
if k<=n then
begin
X[k]:=PrimulElement(k);
if Continuare(k) then Reluare(k+1);
while ExistaSuccesor(k) do
begin
X[k]:=Succesor(k);
if Continuare(k) then Reluare(k+1);
end { while }
end { then }
else PrelucrareaSolutiei;
end; { Reluare }

131

begin
write(’Daţi cardinalul A[’, k, ’]=’); readln(M[k]);
write(’Daţi elementele mulţimii A[’, k, ’]: ’);
for j:=1 to M[k] do read(A[k, j]);
writeln;
end;
Write(’Daţi q=’); readln(q);
Indicator:=false;
Reluare(1);
if Indicator=false then writeln(’Nu există soluţii’);
readln;
end.

Din analiza procedurii Reluare şi a ordinii de parcurgere a elementelor din mul-


ţimile A1, A2, ..., An (fi g. 5.4) rezultă că în cazul cel mai nefavorabil vor fi
generaţi toţi

vectorii X ai produsului cartezian A1A2...An. Prin urmare, complexitatea tempo-


rală a algoritmilor bazaţi pe metoda reluării este, ca şi în cazul trierii, O(mn

), unde

m=max(m1, m2, ..., mn).


Timpul real de execuţie, cerut de un algoritm, depinde în mare măsură de natura

problemei, mai exact, de esenţa condiţiilor de continuare şi ordinea în care apar


ele-
mentele akj în mulţimile A1, A2, ..., An. O bună alegere a condiţiilor de
continuare are

ca efect o importantă reducere a numărului de calcule. În particular, în cazul cel


mai
favorabil, din fi ecare mulţime A1, A2, ..., An va fi testat numai cîte un singur
element
şi, evident, timpul de execuţie va fi proporţional cu n.
Cu regret, în prezent nu există o regulă universală care ar permite formularea
unor condiţii „bune” de continuare pentru orice problemă întîlnită în practică.
Identifi carea acestor condiţii şi, în consecinţă, reducerea timpului de calcul
depinde
de iscusinţa programatorului. Menţionăm că în majoritatea problemelor mulţimile
A1, A2, ..., An nu sînt cunoscute apriori, iar componentele vectorului X pot
aparţine şi
ele unor tipuri structurate de date  tablouri, mulţimi sau articole.

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