Sunteți pe pagina 1din 13

METODA BACKTRACKING

Stiva este acea form de organizare a datelor (structur de date) cu proprietatea c operaiile de introducere i scoatere a datelor se fac n vrful ei. Stivele se pot simula utiliznd vectori. Fie ST(i) un vector. ST(1), ST(2), ..., ST(n) pot reine numai litere sau numai cifre. O variabil K indic n permanent vrful stivei. Exemplificm, n continuare, modul de lucru cu stiva:
A B A

n stiva iniial vid se introduce litera A, vrful stivei va fi la nivelul 1 (k-1); introducem n stiv litera B, deci k va lua valoarea 2; scoatem din stiv pe B (A nu poate fi scos); scoatem din stiv pe A; stiva rmne vid

n mod practic la scoaterea unei variabile din stiv, scade cu 1 valoarea variabilei ce indic vrful stivei, iar atunci cnd scriem ceva n stiv, o eventual valoare rezidual se pierde: Pe un anumit nivel se retine, de regul, o singur informaie (liter sau cifr), ns este posibil; aa cum va rezulta din exemplele, prezentate n lucrare, s avem mai multe informaii, caz n care avem de a face cu stive duble, triple, etc. ntreaga teorie a recursivitii se bazeaz pe structura de tip stiv.

Prezentarea tehnicii Backtracking Aceast tehnic se folosete n rezolvarea problemelor care ndeplinesc simultan urmtoarele condiii: - soluia lor poate fi pus sub forma unui vector S=x1,x2, ...,xn, cu x1 A1, x2 A2 ,xn An - mulimile A1, A2 , ., An sunt mulimi finite, iar elementele lor se consider c se afl ntr-o relaie de ordine bine stabilit; - nu se dispune de o alt metod de rezolvare, mai rapid - x1 x2 , xn pot fi la rndul lor vectori; - A1, A2 , An pot coincide. La ntlnirea unei astfel de probleme, dac nu cunoatem aceast tehnic, suntem tentai s generm toate elementele produsului cartezian A1,A2 ,An si fiecare element s fie testat dac este soluie. Rezolvnd problema n acest mod, timpul de execuie este att de mare, nct poate fi considerat infinit, algoritmul neavnd nici o valoare practic. De exemplu, dac dorim s generm toate permutrile unei mulimi finite A, nu are rost s generm produsul cartezian AxAx.....xA, pentru ca apoi, s testm, pentru fiecare element al acestuia, dac este sau nu permutare (nu are rost s generm 1.1,1.......1, pentru ca apoi s constatm c nu am obinut o permutare, cnd de la a doua cifr 1 ne puteam da seama c cifrele nu sunt distincte). Tehnica Backtracking are la baz un principiu extrem de simplu: - se construiete soluia pas cu pas: x1, x2 ,xn - dac se constat c, pentru o valoare aleas, nu avem cum s ajungem la soluie, se renun la acea valoare i se reia cutarea din punctul n care am rmas.

Concret: - se alege primul element x, ce aparine lui A; - presupunnd generate elementele x1,x2 ,xk , aparinnd mulimilor A1, A2 ,Ak , se alege (dac exist) xk+1 , primul element disponibil din mulimea Ak+1 , apar dou posibiliti : 1) Nu s-a gsit un astfel de element, caz n care caz n care se reia cutarea co nsidernd generate elementele x1,x2 ,xk+1 , iar aceasta se reia de la urmtorul element al mulimii Ak rmas netestat; 2) A fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii de continuare aprnd astfel dou posibiliti: - ndeplinete, caz n care se testeaz dac s-a ajuns la soluie si apar din nou dou posibiliti - s-a ajuns la soluie, se tiprete soluia si se reia algoritmul considernd generate elementele x1,x2 ,xk , (se caut n continuare, un alt element al mulimii Ak , rmas netestat); - nu s-a ajuns la soluie, caz n care se reia algoritmul considernd generate elementele x 1,x2 ,xk , si se caut un prim element xk+2 Ak. - nu le ndeplinete caz n care se reia algoritmul considernd generate elementele x1,x2 ,xk , iar elementul xk-1 se caut ntre elementele mulimii A, rmase netestate. Algoritmii se termin atunci cnd nu exist nici un element x1 A1 netestat. Observaie: tehnica Backtracking are ca rezultat obinerea tuturor soluiilor problemei. n cazul n care se cere o sigur soluie se poate fora oprirea, atunci cnd a fost gsit. Am artat c orice soluie se genereaz sub form de vector. Vom considera c generarea soluiilor se face intr-o stiv. Astfel, x1 A1, se va gsi pe primul nivel al stivei, x2 A2 se va gsi pe al doilea nivel al stivei,... xk Ak se va gsi pe nivelul k al stivei. n acest fel, stiva (notat ST) va arta astfel:

... xk
ST

Nivelul k+1 al stivei trebuie x2 iniializat (pentru a alege, n ordine, elementele mulimii k+1 ). Iniializarea trebuie fcut cu o valoare aflat (n relaia de ordine considerat, pentru mulimea Ak+1 ) naintea x1 tuturor valorilor posibile din mulime. De exemplu, pentru generarea permutrilor mulimii {1,2.....n}, orice nivel al stivei va lua valori de la 1 la n. Iniializarea unui nivel (oarecare) se face cu valoarea 0. Procedura de iniializare o vom numi INIT i va avea doi parametri: k (nivelul care trebuie iniializat si ST (stiva)). Gsirea urmtorului element al mulimii Ak (element care a fost netestat) se face cu ajutorul procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o variabil boolean. n situaia n care am gsit elementul, acesta este pus n stiv i AS ia valoarea TRUE, contrar (nu a rmas un element netestat) AS ia valoarea FALSE.. Odat ales un element, trebuie vzut dac acesta ndeplinete condiiile de continuare (altfel spus, dac elementul este valid). Acest test se face cu ajutorul procedurii VALID (EV,ST,K). Testul dac s-a ajuns sau nu la soluia final se face cu ajutorul funciei SOLUTIE(k) iar o soluie se tiprete cu ajutorul procedurii TIPAR. Prezentm n 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; Observaie: Problemele rezolvate prin aceast metod necesit un timp ndelungat. Din acest motiv, este bine s utilizm metoda numai atunci cnd nu avem la dispoziie un alt algoritm mai eficient. Cu toate c exist probleme pentru care nu se pot elabora ali algoritmi mai eficieni, tehnica backtracking trebuie aplicat numai n ultim instan. Fiind dat o tabl de ah, de dimensiune n, xn, se cer toate soluiile de aranjare a n dame, astfel nct s nu se afle dou dame pe aceeai linie, coloan sau diagonal (dame s nu se atace reciproc). Exemplu: Presupunnd c dispunem de o tabl de dimensiune 4x4, o soluie ar fi urmtoarea: D D D D Observm c o dam trebuie s fie plasat singur pe linie. Plasm prima dam pe linia 1, coloana 1. D

A doua dam nu poate fi D D

aezat dect n coloana 3.

Observm c a treia dam nu poate fi plasat n linia 3. ncercm atunci plasarea celei de -a doua dame n coloana 4. D D

A treia dam nu poate fi plasat dect n coloana 2.

D D D n aceast situaie dama a patra nu mai poate fi aezat. ncercnd s avansm cu dama a treia, observm c nu este posibil s o plasm nici n coloana 3, nici n coloana 4, deci o vom scoate de pe tabl. Dama a doua nu mai poate avansa, deci i ea este scoas de pe tabl. Avansm cu prima dam n coloana 2. D

A doua dam nu poate fi D D

aezat dect n coloana 4.

Dama a treia se aeaz n prima D D D

coloan.

Acum este posibil s plasm a patra dam n coloana 3 si astfel am obinut o soluie a problemei. D D D D Algoritmul continu n acest mod pn cnd trebuie scoas de pe tabl prima dam. Pentru reprezentarea unei soluii putem folosi un vector cu n componente (avnd n vedere c pe fiecare linie se gsete o singur dam). Exemplu pentru soluia gsit avem vectorul ST ce poate fi asimilat unei stive. Dou dame se gsesc pe aceeai diagonal dac si numai dac este ndeplinit condiia: |st(i) st(j)|=|i-j| ( diferena, n modul, ntre linii si coloane este aceeai). ST(4)

3 1 4 2

ST(3) n general ST(i)=k semnific faptul c pe linia i dama ocup poziia k. ST(1) Exemplu: n tabla 4 x4 avem situaia:

ST(2)

D D D D D D D D

st(1)= 1 i = 1 st(3)= 3 j = 3 |st(1) - st(3)| = |1 3| = 2 |i j| = |1 3| = 2 sau situaia st(1) = 3 i = 1 st(3) = 1 j = 3 |st(i) - st(j)| = |3 1| = 2 |i j| = |1 3| = 2

ntruct doua dame nu se pot gsi n aceeai coloan, rezult c o soluie este sub form de permutare. O prim idee ne conduce la generarea tuturor permutrilor si la extragerea soluiilor pentru problema ca dou dame s nu fie plasate n aceeai diagonal. A proceda astfel, nseamn c lucrm conform strategiei backtracking. Aceasta presupune ca imediat ce am gsit dou dame care se atac, s relum cutarea. lat algoritmul, conform strategiei generate de backtracking: - n prima poziie a stivei se ncarc valoarea 1, cu semnificaia c n linia unu se aeaz prima dam n coloan. - Linia 2 se ncearc aezarea damei n coloana 1, acest lucru nefiind posibil ntruct avem doua dame pe aceeai coloan. - n linia 2 se ncearc aezarea damei n coloana 2 , ns acest lucru nu este posibil, pentru c damele se gsesc pe aceiai diagonal (|st(1)-st(2)|=|1-2|); - Aezarea damei 2 n coloana 3 este posibil. - Nu se poate plasa dama 3 n coloana 1, ntruct n liniile 1-3 damele ocupa acelai coloan. - i aceast ncercare eueaz ntruct damele de pe 2 i 3 sunt pe aceeai diagonal. - Damele de pe 2-3 se gsesc pe aceeai coloan. - Damele de pe 2-3 se gsesc pe aceeai diagonal. - Am cobort n stiv mutnd dama de pe linia 2 i coloana 3 n coloana 4. Algoritmul se ncheie atunci cnd stiva este vid. Semnificaia procedurilor utilizate este urmtoarea: INIT - nivelul k al stivei este iniializat cu 0; SUCCESOR - mrete cu 1 valoarea aflat pe nivelul k al stivei n situaia n care aceasta este mai mic dect n i atribuie variabilei EV valoarea TRUE, n caz contrar, atribuie variabilei EV valoarea FALSE; VALID - valideaz valoarea pus pe nivelul k al stivei, verificnd dac nu avem dou dame pe aceeai linie (st(k)=st(i)), sau dac nu avem dou dame pe aceeai diagonal (st(k) -st(i)=|k-i|)caz n care variabilei EV i se atribuie FALSE; n caz contrar, variabilei EV i se atribuie TRUE; SOLUTIE - verific dac stiva a fost completat pn la nivelul n inclusiv; TIPAR - tiprete o soluie.

Backtracking generare permutari si combinari


14 Cu totii stim ca Backtracking este una din cele mai cunoscute tehnici de programare. Ideea din spatele acestui algoritm este de a genera toate solutiile posibile si a le abandona in cazul in care observa ca nu indeplinesc conditiile necesare. Datorita generarii tuturor solutiilor, complexitatea algoritmului este foarte mare, dar duce sigur la generarea tuturor posibilitatilor valide. Din aceasta cauza, e o tehnica foarte cunoscuta in randul programatorilor (in special a celor care participa la concursuri si olimpiade de informatica) deoarece este considerata solutia ce trebuie abordata in cazul in care nu ai nici o idee.

Structura unei functii backtracking


?
1 2 3 4 5 6 7 8 9 10 11 void back(int k) { if(reject_sol(k)) return; if(accept_sol(k)) show_sol(k); for(i=0;i<n;i++) { v[k]=set(); back(k+1); v[k]=unset(); } }

Generarea tuturor permutarilor


Problema : Sa se genereze toate permutarile multimii {1, 2, N}, in ordine lexicografica. Solutie : Din moment ce problema ne cere generarea tuturor solutiilor, este evident ca vom avea nevoie de o abordare backtracking. ?
1 2 3 4 5 6 7 8 9 10 11 12 13 #include<cstdio> int a[10],b[10]; void back(int k,int len) { if(k-1 == len) //afisam solutia { for(int i = 1; i <= len;i++) printf("%d ",a[i]); printf("\n"); } else {

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

for(int i = 1; i <= len; i++) if(!b[i]) //daca valoarea nu-i folosita { a[k] = i; b[i] = 1; //o folosim back(k+1,len); //trecem la pasul urmator b[i] = 0; //o eliberam } } } int main() { freopen("permutari.in","r",stdin); freopen("permutari.out","w",stdout); int n; scanf("%d",&n); back(1,n); fclose(stdin); fclose(stdout); return 0; }

Generarea tuturor combinarilor de n luate cate k


Problema : Sa se genereze toate combinarile de N luate cate K in ordine lexicografica. Solutie : Din moment ce si aceasta problema ne cere generarea tuturor posibilitatilor este evident ca solutia este una ce are nevoie de o abordare backtracking. ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include<cstdio> int a[19],b[19];

void back(int k,int len,int max) { if(k-1 == max) //afisam solutia { for(int i = 1; i <= max;i++) printf("%d ",a[i]); printf("\n"); } else { for(int i = 1; i <= len; i++) if(!b[i] && a[k-1] < i) //ne asiguram ca generam solutiile crescatoar { a[k] = i; b[i] = 1; //o folosim back(k+1,len,max); //trecem la pasul urmator b[i] = 0; //o eliberam } } } int main() { freopen("combinari.in","r",stdin); freopen("combinari.out","w",stdout); int n,k; scanf("%d %d",&n,&k); back(1,n,k); fclose(stdin); fclose(stdout);

33 34

return 0; }

Aplicatii Backtracking
1. Generarea aranjamentelor 2. Problema damelor 3. Problema turelor 4. Generarea produsului cartezian a n multimi 5. Sa se genereze n perechi de parantezari care se inchid corect 6. Cel mai lung prefix

Concluzie
Aceasta metoda este extrem de raspandita si de utila in cazul problemelor in care generarea tuturor solutiilor este necesara. De asemenea, in cazul concursurilor este una din cele mai populare modalitati de furare a catorva puncte.

Problema comis-voiajorului
Un comis voiajor trebuie s viziteze un numr n de orae. Iniial, el se afl ntr -unul dintre ele, notat 1. Comis voiajorul dorete s nu treac de dou ori prin acelai ora, iar la ntoarcere s revin n oraul din care a plecat. Cunoscnd legturile existente ntre orae, se cere s se tipreasc toate drumurile posibile pe care le poate efectua comis voiajorul.Drumurile dintre orase sunt date sub forma unei matrici a[i][j]=1 daca intre orasul i si j exista drum si a[i][j]=0 daca nu exista drum intre orasul i si orasul j.

#include<iostream.h> #include<conio.h> #include<math.h> int st[20],n,k,a[10][10]; void init() {st[k]=1;} int succesor() {if (st[k]<n) {st[k]++; return 1; } else return 0;} int valid() {if( a[st[k-1]][st[k]]==0) return 0; for(int i=1;i<k;i++) if(st[i]==st[k] ) return 0; if((k==n) && (a[1][st[k]]==0)) return 0; return 1;}

int sol() {return (k==n);} void tipar() {for(int i=1;i<=n;i++) cout<<st[i]<<" "; cout<<endl; } void bkt() {int as;k=2; init(); while(k>0) { do {} while ((as=succesor()) && !valid()); if (as) if (sol()) tipar(); else {k++;init();} else k--; } } void main() {cout<<"numarul de orase=";cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; st[1]=1; bkt(); }

Problema colorarii hartilor


Fiind data o harta cu n tari, se cer toate solutiile de colorare a hartii, utilizand cel mult patru culori, astfel incat doua tari ce au frontiera comuna sa fie colorate diferit. Este demonstrat faptul ca sunt suficiente numai patru culori pentru ca orice harta sa poata fi colorata.

#include<iostream.h> #include<conio.h> #include<math.h> int st[20],n,k; void init() {st[k]=0;}

int succesor() {if (st[k]<4) {st[k]++; return 1; } else return 0;} int valid() {for(int i=1;i<k;i++) if(st[i]==st[k] && a[i][k]==1) return 0; return 1;} int sol() {return (k==n);} void tipar() {for(int i=1;i<=n;i++) cout<<"tara numarul"<<i<<" culoarea"<<st[i]<<endl; cout<<endl; } void bkt() {int as;k=1; init(); while(k>0) { do {} while ((as=succesor()) && !valid()); if (as) if (sol()) tipar(); else {k++;init();} else k--; } } main() {cout<<"numarul de tari=";cin>>n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) cin>>a[i][j]; bkt(); }

10

Problema celor n dame. Fiind data o tabla de sah nn se cer toate


solutiile de aranjare a n dame, astfel incat sa nu se afle doua dame pe aceeasi linie, coloana sau diagonala (damele sa nu se atace reciproc). Exemplu: Presupunand ca dispunem de o tabla de dimensiune 44, o solutie ar fi urmatoarea: D D D D

Cum procedam? 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 pe coloana a 3-a. D D

#include<iostream> #include<conio.h> #include<math.h> using namespace std; int st[100],top,n; int init(int st[],int top) { st[top]=0; }

11

int succesor(int st[],int top) { if (st[top]<n) { st[top]++; return 1; } else return 0; } int valid(int st[],int top) { for(int i=1;i<top;i++) if(st[i]==st[top] || fabs(st[top]-st[i])==fabs(top-i)) return 0; return 1; } int solutie(int st[],int top) { return (top==n); } int tipar(int st[],int top) { for(int i=1;i<=n;i++) cout<<st[i]; cout<<endl; } int back() { top=1; init(st,top); while(top>0) { while(succesor(st,top)) { if(valid(st,top)) if(solutie(st,top))

12

tipar(st,top); else {

13

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