METODA BACKTRACKING





METODA BACKTRACKING






Stiva este acea forma de organizare a datelor (structura de date) cu proprietatea ca operatiile de introducere si scoatere a datelor se fac in varful ei.­

Stivele se pot simula utilizand vectori.

Fie ST(i) un vector. ST(1), ST(2), , ST(n) pot retine numai litere sau numai cifre. O variabila K indica in permanenta varful stivei.

Exemplificam, in continuare, modul de lucru cu stiva:


In stiva initial vida se introduce litera A, varful stivei va fi la nivelul 1 (k-1);


introducem in stiva litera B, deci k va lua valoarea 2;


scoatem din stiva pe B (A nu poate fi scos);


  scoatem din stiva pe A; stiva ramane vida



In mod practic la scoaterea unei variabile din stiva, scade cu 1 valoarea variabilei ce indica varful stivei, iar atunci cand scriem ceva in stiva, o eventuala valoare reziduala se pierde:

Pe un anumit nivel se retine, de regula, o singura informatie (litera sau cifra), insa este posibil; asa cum va rezulta din exemplele, prezentate in lucrare, sa avem mai multe informatii, caz in care avem de a face cu stive duble, triple, etc.

Intreaga teorie a recursivitatii se bazeaza pe structura de tip stiva.



Prezentarea tehnicii Backtracking


Aceasta tehnica se foloseste in rezolvarea problemelor care indeplinesc simultan urmatoarele conditii:

- solutia lor poate fi pusa sub forma unui vector S=x1,x2, ,xn, cu x1 € A1,

x2 € A2 …,xn € An

- multimile A1, A2 , …., An sunt multimi finite, iar elementele lor se considera ca se afla intr-o relatie de ordine bine stabilita;

- nu se dispune de o alta metoda de rezolvare, mai rapida

- x1 x2 …, xn pot fi la randul lor vectori;

- A1, A2 …, An pot coincide.


La intalnirea unei astfel de probleme, daca nu cunoastem aceasta tehnica, suntem tentati sa generam toate elementele produsului cartezian A1,A2 …,An si fiecare element sa fie testat daca este solutie. Rezolvand problema in acest mod, timpul de executie este atat de mare, incat poate fi considerat infinit, algoritmul neavand nici o valoare practica.

De exemplu, daca dorim sa generam toate permutarile unei multimi finite A, nu are rost sa generam produsul cartezian AxAx..xA, pentru ca apoi, sa testam, pentru fiecare element al acestuia, daca este sau nu permutare (nu are rost sa generam 1.1,1.1, pentru ca apoi sa constatam ca nu am obtinut o permutare, cand de la a doua cifra 1 ne puteam da seama ca cifrele nu sunt distincte).

Tehnica Backtracking are la baza un principiu extrem de simplu:

- se construieste solutia pas cu pas: x1, x2 …,xn

- daca se constata ca, pentru o valoare aleasa, nu avem cum sa ajungem la solutie, se renunta la acea valoare si se reia cautarea din punctul in care am ramas.


Concret:

- se alege primul element x, ce apartine lui A;

- presupunand generate elementele x1,x2 …,xk , apartinand multimilor A1,

A2 …,Ak , se alege (daca exista) xk+1 , primul element disponibil din multimea Ak+1 , apar doua posibilitati :

1) Nu s-a gasit un astfel de element, caz in care caz in care se reia cautarea considerand generate elementele  x1,x2 …,xk+1 , iar aceasta se reia de la urmatorul element al multimii Ak ramas netestat;

2) A fost gasit, caz in care se testeaza daca acesta indeplineste anumite conditii de continuare aparand astfel doua posibilitati:

- indeplineste, caz in care se testeaza daca s-a ajuns la solutie si apar din nou doua posibilitati

- s-a ajuns la solutie, se tipareste solutia si se reia algoritmul considerand generate elementele x1,x2 …,xk , (se cauta in continuare, un alt element al multimii Ak , ramas netestat);

- nu s-a ajuns la solutie, caz in care se reia algoritmul considerand generate elementele x1,x2 …,xk , si se cauta un prim element xk+2 € Ak.

- nu le indeplineste caz in care se reia algoritmul considerand generate elementele x1,x2 …,xk , iar elementul xk-1 se cauta intre elementele multimii A, ramase netestate.

Algoritmii se termina atunci cand nu exista nici un element x1 € A1 netestat.

Observatie: tehnica Backtracking are ca rezultat obtinerea tuturor solutiilor problemei. In cazul in care se cere o sigura solutie se poate forta oprirea, atunci cand a fost gasita.


Am aratat ca orice solutie se genereaza sub forma de vector. Vom considera ca generarea solutiilor se face intr-o stiva. Astfel, x1 € A1, se va gasi pe primul nivel al stivei, x2 € A2 se va gasi pe al doilea nivel al stivei, xk € Ak se va gasi pe nivelul k al stivei. In acest fel, stiva (notata ST) va arata astfel:







ST




Nivelul k+1 al stivei trebuie initializat (pentru a alege, in ordine, elementele multimii k+1 ). Initializarea trebuie facuta cu o valoare aflata (in relatia de ordine considerata, pentru multimea Ak+1 ) inaintea tuturor valorilor posibile din multime. De exemplu, pentru generarea permutarilor multimii , orice nivel al stivei va lua valori de la 1 la n. Initializarea unui nivel (oarecare) se face cu valoarea 0. Procedura de initializare o vom numi INIT si va avea doi parametri: k (nivelul care trebuie initializat si ST (stiva)).

Gasirea urmatorului element al multimii Ak (element care a fost netestat) se face cu ajutorul procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o variabila booleana. In situatia in care am gasit elementul, acesta este pus in stiva si AS ia valoarea TRUE, contrar (nu a ramas un element netestat) AS ia valoarea FALSE..

Odata ales un element, trebuie vazut daca acesta indeplineste conditiile de continuare (altfel spus, daca elementul este valid). Acest test se face cu ajutorul procedurii VALID (EV,ST,K).

Testul daca s-a ajuns sau nu la solutia finala se face cu ajutorul functiei SOLUTIE(k) iar o solutie se tipareste cu ajutorul procedurii TIPAR. Prezentam in continuare rutina Backtracking:


k:=1; init(1,st);

while k>0 do begin

repeat succesor (as, st, k) ; .

if as then valid(ev,st,k)

until (not as) or (as and ev) ;

if as then

if solutie(k) then tipar

else begin

k:=k+l;

init ( k, st );

end;

else k: k-1

end;


Observatie: Problemele rezolvate prin aceasta metoda necesita un timp indelungat. Din acest motiv, este bine sa utilizam metoda numai atunci cand nu avem la dispozitie un alt algoritm mai eficient. Cu toate ca exista probleme pentru care nu se pot elabora alti algoritmi mai eficienti, tehnica backtracking trebuie aplicata numai in ultima instanta.

Fiind data o tabla de sah, de dimensiune n, xn, se cer toate solutiile de aranjare a n dame, astfel incat sa nu se afle doua dame pe aceeasi linie, coloana sau diagonala (dame sa nu se atace reciproc).

Exemplu: Presupunand ca dispunem de o tabla de dimensiune 4x4, o solutie ar fi urmatoarea:


D






D

D






D








Observam ca o dama trebuie sa fie plasata singura pe linie. Plasam prima dama pe linia 1, coloana 1.


D






















A doua dama nu poate fi asezata decat in coloana 3.

D






D


















Observam ca a treia dama nu poate fi plasata in linia 3. Incercam atunci plasarea celei de-a doua dame in coloana 4.

D







D
















A treia dama nu poate fi plasata decat in coloana 2.

D







D


D













In aceasta situatie dama a patra nu mai poate fi asezata.

Incercand sa avansam cu dama a treia, observam ca nu este posibil sa o plasam nici in coloana 3, nici in coloana 4, deci o vom scoate de pe tabla. Dama a doua nu mai poate avansa, deci si ea este scoasa de pe tabla. Avansam cu prima dama in coloana 2.


D





















A doua dama nu poate fi asezata decat in coloana 4.



D






D















Dama a treia se aseaza in prima coloana.



D






D

D















Acum este posibil sa plasam a patra dama in coloana 3 si astfel am obtinut o solutie a problemei.



D






D

D






D







Algoritmul continua in acest mod pana cand trebuie scoasa de pe tabla prima dama.

Pentru reprezentarea unei solutii putem folosi un vector cu n componente (avand in vedere ca pe fiecare linie se gaseste o singura dama).

Exemplu pentru solutia gasita avem vectorul ST ce poate fi asimilat unei stive.

Doua dame se gasesc pe aceeasi diagonala daca si numai daca este indeplinita conditia: |st(i)-st(j)|=|i-j| ( diferenta, in modul, intre linii si coloane este aceeasi).

ST(4)

ST(3) In general ST(i)=k semnifica faptul ca pe linia i dama ocupa pozitia k.                       ST(2)

ST(1)


Exemplu: in tabla 4 x4 avem situatia:


D






D

D






D


st(1) i = 1

st(3)= 3 j = 3

|st(1) - st(3)| = |1 – 3| = 2

|i – j| = |1 – 3| = 2


sau situatia



D






D

D






D


st(1) = 3 i = 1

st(3) = 1 j = 3

|st(i) - st(j)| = |3 – 1| = 2

|i – j| = |1 – 3| = 2



Intrucat doua dame nu se pot gasi in aceeasi coloana, rezulta ca o solutie este sub forma de permutare. O prima idee ne conduce la generarea tuturor permutarilor si la extragerea solutiilor pentru problema ca doua dame sa nu fie plasate in aceeasi diagonala. A proceda astfel, inseamna ca lucram conform strategiei backtracking. Aceasta presupune ca imediat ce am gasit doua dame care se ataca, sa reluam cautarea.

lata algoritmul, conform strategiei generate de backtracking:

- In prima pozitie a stivei se incarca valoarea 1, cu semnificatia ca in linia unu se aseaza prima dama in coloana.

- Linia 2 se incearca asezarea damei in coloana 1, acest lucru nefiind posibil intrucat avem doua dame pe aceeasi coloana.

- In linia 2 se incearca asezarea damei in coloana 2 , insa acest lucru nu este posibil, pentru ca damele se gasesc pe aceiasi diagonala (|st(1)-st(2)|=|1-2|);

- Asezarea damei 2 in coloana 3 este posibila.

- Nu se poate plasa dama 3 in coloana 1, intrucat in liniile 1-3 damele ocupa acelasi coloana.

- Si aceasta incercare esueaza intrucat damele de pe 2 si 3 sunt pe aceeasi diagonala.

- Damele de pe 2-3 se gasesc pe aceeasi coloana.

­- Damele de pe 2-3 se gasesc pe aceeasi diagonala.

­- Am coborat in stiva mutand dama de pe linia 2 si coloana 3 in coloana 4.


Algoritmul se incheie atunci cand stiva este vida. Semnificatia procedurilor utilizate este urmatoarea:

INIT - nivelul k al stivei este initializat cu 0;

SUCCESOR - mareste cu 1 valoarea aflata pe nivelul k al stivei in situatia in care aceasta este mai mica decat n si atribuie variabilei EV valoarea TRUE, in caz contrar, atribuie variabilei EV valoarea FALSE;

VALID - valideaza valoarea pusa pe nivelul k al stivei, verificand daca nu avem doua dame pe aceeasi linie (st(k)=st(i)), sau daca nu avem doua dame pe aceeasi diagonala (st(k)-st(i)=|k-i|)caz in care variabilei EV i se atribuie FALSE; in caz contrar, variabilei EV i se atribuie TRUE;

SOLUTIE - verifica daca stiva a fost completata pana la nivelul n inclusiv;

TIPAR - tipareste o solutie.