Sunteți pe pagina 1din 15

BACKTRACKING

Proiect realizat de Pintilie Andreea Raluca Clasa a X a D Profesor coordonator: Iordachi Lizeta

Backtracking este numele unui algoritm general de descoperire a tuturor soluiilor unei probleme de calcul, algoritm ce se bazeaz pe construirea incremental de soluii-candidat, abandonnd fiecare candidat parial imediat ce devine clar c acesta nu are anse s devin o soluie valid.

TEHNICA BACKTRACKING
Aceast tehnic poate fi utilizat pentru rezolvarea problemelor de cutare. Cutarea efectuat este exhaustiv, putnd fi folosit pentru generarea tuturor soluiilor posibile. 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. Se folosete n rezolvarea problemelor care ndeplinesc simultan urmtoarele condiii: Soluia lor poate fi pus sub forma unui vector V = x1,x2,x3, . xn, cu x1A1, . Xn An Mulimile A1, A2, An sunt mulimi finite, iar elementele lor se afl ntr-o ordine bine stabilit Nu se dispune de o metod de rezolvare mai rapid

ALGORITMUL METODEI
se alege primul element x1, ce aparine lui A1; presupunnd generate elementele x1 xk, vom avea 2 posibiliti: nu s-a gsit un astfel de element, caz n care se reia cutarea, considernd generate elementele x1 xk-1, iar aceasta se reia de la urmtorul element Ak, rmas netestat. a fost gsit, caz n care se testeaz dac acesta ndeplinete anumite condiii (rspunsul poate fi verificat de o funcie Validare care returneaz true sau false). dac le ndeplinete, se testeaz dac s-a ajuns la soluie (se utilizeaz funcia Soluie, care returneaz true dac s-a ajuns la soluie) dac s-a ajuns la soluie, se tiprete i se continu algoritmul pentru gsirea unei alte soluii, considerndu-se generate x1 xk, iar elementul xk+1 se caut printre elementele mulimii Ak+1 rmase netestate dac nu s-a ajuns la soluie se reia algoritmul considerndu-se generate elementele x1, xk, xk+1 dac nu le ndeplinete se reia algoritmul considernd generate x1xk, iar elementul xk+1 se caut printre elementele mulimii Ak+1 rmase netestate

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;

PROTOTIP RECURSIV
//Generarea permutarilor nivelul n

#include<iostream> using namespace std; int st[15],n;

void back(int k) //incarcarea nivelului k {for(int i=1;i<=n;i++) //caut printre toate nr de la 1 la n {st[k]=i; //le incarc pe rand in stiva if(valid(k)) //daca sunt valide void tipar(int k) //afisarea solutiei if(solutie(k)) //daca am ajuns la solutie {for(int i=1;i<=k;i++) cout<<st[i]<<' '; tipar(k); cout<<endl;} else back(k+1); //daca nu am solutie, int valid(int k) //verifica daca elementul de pe inseamna ca am // o "bucatica" de solutie si urc pe nivelul k este valid urmatorul nivel in stiva { } for(int i=1;i<k;i++) //caut elementul de pe } nivelul k pe nivelele anterioare if(st[i]==st[k]) return 0; //daca il gasesc, elementul nu e valid int main() return 1;} {cin>>n; back(1);//incep incarcarea stivei cu nivelul 1 int solutie(int k) } {return k==n;}//am solutie cand am ajuns la

PROTOTIP ITERATIV
//generarea permutarilor #include<iostream> #include<math.h> using namespace std; int n,st[100]; void tipar(int n) {for(int i=1;i<=n;i++) cout<<st[i]<<' '; cout<<endl;} int valid(int k) {for(int j=1;j<k;j++) if (st[k]==st[j]) return 0; return 1;} {if (st[k]<n)//daca elementul din varf mai poate fi marit {st[k]++;//il maresc if (valid(k))//daca e valid if (k==n) //daca am ajuns la nivelul n, am solutie tipar(n);//si o tiparesc else st[++k]=0;//altfel, cresc k si resetez continutul stivei } else k--; //inseamna ca st[k]==n si cobor in stiva, pentru a mari continutul nivelului precedent } }

void back() int main() {int k=1;//plec de la nivelul 1 { st[1]=0;//initializez nivelele cu o valoare cu 1 cin>>n; mai mica decat cea mai mica valoare pe care o back(); pot avea in stiva } while (k>0)//cat timp mai sunt in stiva

PROBLEME REZOLVATE

ENUNT : Fie n numar natural nenul.Scrieti un program de generare a permutarilor de ordin n a elementelor multimii {1, 2, 3,..., n}. EXEMPLU: Pentru n=3 programul va genera 123 132 213 231 312 321

SOLUTIE: Permutarile de ordin n reprezinta toate posibilitatile de a aranja elementele unei multimi de n elemente. I. Solutia x[1]......x[n] - x[i] va avea ca valoare un element al multimii II. x[k] poate avea ca valoare orice valoare din intervalul [1,n] III. Valid - elementele trebuie sa fie distincte x[k] trebuie sa fie diferit de x[1]...x[k-1] Implementare #include<iostream> using namespace std; char sp[]=" ";

int Valid(int k) { int i; for(i=1;i<=k-1;i++) if (x[k]==x[i]) return 0; return 1; } void BackRec(int k) { int i; for(i=1;i<=n;i++) { x[k]=i; if (Valid(k)) if (k==n) Afisare(); else BackRec(k+1); } }

int x[10], n, nrsol=0; void Afisare() { int i; cout<<sp; for(i=1;i<=n;i++) cout<<x[i]<<" "; cout<<endl; nrsol++; if (nrsol%23==0) cin.get(); }

int main() { cout<<endl<<endl<<sp<<"Permutarile primelor n numere naturale (n<10)"<<endl; cout<<endl<<sp<<" Dati valoarea lui n: "; cin>>n; cout<<endl; BackRec(1); cout<<endl<<sp<<"Numar solutii: "<<nrsol; return 0; }

GENERAREA PRODUSULUI CARTEZIAN


ENUNT : Fie n numar natural nenul si A1, A2, ... An n multimi cu L1, L2, .... Ln elemente. Scrieti un program de generare a elementelor produsului cartezian A1 x A2 x A3 x ... x An EXEMPLU: Pentru n=3 si L=(1,2,3) programul va genera {1 1 1} {1 1 2} {1 1 3} {1 2 1} {1 2 2} {1 2 3} SOLUTIE: I. Solutia x[1]......x[n]. Elementul x[i] va avea ca valoare un element al multimii Ai. II. x[k] poate avea ca valoare orice valoare din intervalul [1,Lk]. III. Valid - nu este necesar

Implementare #include<iostream> using namespace std; char sp[]=" "; int x[20], n, nrsol=0, a[20]; void Afisare() {int i,j; cout<<sp; for(i=1;i<=n;i++) cout<<x[i]<<" "; cout<<endl; nrsol++; if (nrsol%24==0) cin.get(); } void BackRec(int k) {int i; for(i=1;i<=a[k];i++) {x[k]=i; if (k==n) Afisare(); else BackRec(k+1);

} } int main() {int i; cout<<endl<<endl<<sp<<"Produsul cartezian a n multimi de cardinal a1, a2, ... an"<<endl; cout<<endl<<sp<<" Dati valoarea lui n: "; cin>>n; cout<<endl<<sp<<" Dati cardinalul fiecarei multimi: "<<endl<<endl; for (i=1;i<=n;i++) { cout<<sp<<" Multimea "<<i<<": "; cin>>a[i]; } BackRec(1); cout<<endl<<sp<<"Numar solutii: "<<nrsol; return 0; }

PROBLEMA COLR N REGINE


O s exemplificm tehnica cutrii cu reveniri cu ajutorul unei probleme clasice: cum putem amplasa N regine pe o tabl de ah cu dimensiuni N x N astfel nct acestea s nu se atace dou cte dou. Este evident c nu putem amplasa dect o singur regin pe linie sau pe coloan i n final fiecare linie va avea amplasat cte o regin. De aceea vom ncerca amplasarea linie cu linie, ncepnd cu prima linie. Atunci cnd ncercm s amplasm o regin pe o linie ncepem cu prima coloan i continum cu urmtoarele, pn cnd gsim o poziie valid. n momentul n care nu mai gsim nici o poziie valid pe o linie vom reveni la linia anterioar, unde vom cuta urmtoarea poziie.

PROBLEMA CELOR N REGINE


#include <iostream> using namespace std; int n,st[50],k; void tipar() {int i,j; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) if(st[i]==j) cout<<"d"<<" "; Else cout<<"*"<<" "; cout<<endl; } cout<<endl; } int valid(int k) { int i; for(i=1;i<k;i++) if(st[k]==st[i] || abs(st[k]-st[i])==abs(k-1)) //verificare pentru a vedea daca 2 regine se ataca intre ele return 0; return 1; } void back(int k) {int i; if(k==n+1) tipar(); else for(i=1;i<=n;i++) { st[k]=i; if(valid(k)) back(k+1); } } int main() { cout<<"n="; cin>>n; back(1); return 0; }

PLATA UNEI SUME


#include <iostream> {cout<<st[j]<<" * "<<a[j]<<" "<<endl; } using namespace std; else int S,st[50],a[50],n,k; if(suma(k)<S && k<n) int suma(int k) back(k+1); }} {int i,x=0; int main() for(i=1;i<=k;i++) x=x+st[i]*a[i]; {int i; return x; } cout<<"n= "; void back(int k) cin>>n; {int i,j; cout<<"S="; for(i=0;i<=S/a[k];i++) //se parcurge pana cin>>S; la numarul de bancnote (de un singur tip ) for(i=1;i<=n;i++) cu care poate fii platita suma. //(Ex. S=10 cin>>a[i]; ron; a[k]=5 ron 10/5=2 bacnote back(1); {st[k]=i; return 0; } if(suma(k)==S) for(j=1;j<=k;j++)

SA SE AFISEZE TOATE ANAGRAMELE UNUI CUVANT CITIT DE LA TASTATURA.


#include <iostream> #include<string> using namespace std; int n; char v[1000],st[50]; int k; void tipar() {int i; {for(i=1;i<=n;i++) cout<<v[st[i]-1]<<" "; // -1 deoarece sirul de caractere pleaca de la 0 cout<<endl;} } int valid(int k) {int i; for(i=1;i<k;i++) if(st[k]==st[i]) return 0; return 1;} void back(int k) {int i; if(k==n+1) tipar(); else for(i=1;i<=n;i++) {st[k]=i; if(valid(k)) back(k+1);} } int main() {int i; cin.get(v,1000); cin.get(); n=strlen(v); back(1); return 0; }