Sunteți pe pagina 1din 23

ELEV: BALMUS IONUT PROFESOR COORDONATOR: DIMITRIEVICI LUCIAN TRAIAN

Cuprins
Backtracking iterativ 1) Definiie 2) Probleme prototip 3) Tipul de probleme la care se aplic metoda 4) Mecanism general 5) Rutina 6) Problema permutarilor 7) Submultimile unei multimi 8) Problema permutarilor literelor unui cuvant Backtracking recursiv

1) Rutina 2) Implementarea codului 3) Plata unei sume de bani 4) Problema calului

DEFINIIE Metoda Backtracking este o metod sau o tehnic de programare care construiete progresiv soluia final ncepnd de la soluia nul sau vid i alegnd pentru fiecare component a sa o valoare din mulimea soluiilor posibile. Metoda se traduce prin revenire sau cale ntoars sau drum napoi deoarece de fiecare dat cnd nu se poate nainta ne ntoarcem cu un pas sau mai muli napoi . Problema 1 prototip:

Se dau dou mulimi: S1={A, B, C} i S2={M, N}. Determinai toi vectorii formai din dou componente x1 , x2 aparinnd mulimii S1S2 astfel nct dac x1 este A sau B, x2 nu poate fi M.
Soluii: soluii rezultat: x{(A, M), (A, N), (B, M), (B, N), (C, M), (C, N)} soluii rezultat: x{(A, N), (B, N), (C, M), (C, N)}

Tipul de probleme la care se aplic metoda


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 x1A1, x2A2, , xnAn; 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 o alt metod de rezolvare mai rapid. La ntlnirea unei astfel de probleme, dac nu cunoatem aceast tehnic, suntem tentai s generm toate elementele produsului cartezian A1A2An i 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. Pentru fiecare problem sunt date anumite condiii sau relaii ntre componentele vectorului ce sunt numite condiii interne (de continuare). Pentru a determina toate soluiile rezultat fr a genera toate soluiile posibile este folosit tehnica ntoarcerii cu revenire.

Mecanismul general
Metoda urmrete s evite generarea tuturor soluiilor posibile. n acest scop elementele vectorului x=(x1, x2, , xn) primesc pe rnd valori n sensul c lui xk i se atribuie o valoare numai dac au fost deja atribuite valori pentru componentele x1, x2, , xk-1. Odat stabilit o valoare pentru xk-1 nu se trece direct la atribuirea unei valori pentru xk; nti se verific condiia de continuare referitoare la componentele x1, x2, , xk-1. Dac au fost ndeplinite condiiile de continuare atunci se alege o valoare pentru xk iar nendeplinirea lor exprim faptul c oricum am alege componentele xk, xk+1, , xn nu vom putea ajunge la o soluie de tip rezultat. Asta nseamn c acele condiii de continuare sunt strict necesare pentru obinerea unei soluii. n cazul nendeplinirii condiiilor de continuare va trebui s se fac o nou alegere pentru xk sau dac mulimea Sk a fost epuizat se va ncerca o nou alegere pentru componenta xk-1 dup care se face o nou alegere pentru xk. Aceast revenire la componenta anterioar prin micorarea lui k d numele metodei. n unele probleme vom ntlni att condiii de continuare ct i condiii interne ntre ele existnd o strns legtur. n alte tipuri de probleme condiiile interne vor fi aceleai cu condiiile de continuare i atunci cnd pasul k va atinge valoarea n condiiile de continuare sunt chiar condiiile interne. Prin aceast metod orice vector este construit progresiv ncepnd cu prima component i mergnd ctre ultima cu eventualele reveniri asupra valorilor atribuite anterior (cu unul sau mai muli pai napoi att timp ct este posibil revenirea).

Prin atribuiri sau ncercri de atribuiri euate din cauza nerespectrii condiiilor de continuare, anumite valori sunt consumate sau testate i vom nota cu Ck mulimea valorilor consumate (testate) fiecare mulime Ck fiind inclus cu posibilitate de egal n Sk.

v1, v2, , vk sunt valorile curente pentru componentele x1, x2, , xk


O configuraie oarecare pentru aceast metod este reprezentat astfel:
v1, v2, , vk-1 xk, xk+1, , xn c1, c2, , ck-1 Ck, vid, , vid

Pn la xk toate componentele au primit valorile v1, v2, , vk-1 n ncercarea de a construi un vector soluie. Aceste valori satisfac condiiile de continuare pentru componenta xk. Urmeaz s se fac o atribuire din Sk-Ck, unde Ci reprezint mulimea valorilor consumate (testate). Aplicarea metodei Backtracking ncepe n situaia n care nici o valoare nu a fost consumat i se ncearc atribuirea asupra primei componente (acest lucru presupune c mulimile Ck sunt vide).

Rutina
Atunci cnd mulimile de valori posibile sunt distincte S1SSSn se citesc mulimile S1,S2,,Sn se iniializeaz C1, C2, , Cn cu mulimea vid k = 1; //se iniializeaz pasul de lucru cu 1 while (k > 0) do //configuraia nu e final if (k == n+1 ) atunci //s-a depit dimensiunea vectorului se tiprete soluia se scade cu o unitate pasul de lucru else dac Ck Sk atunci //mai exist valori netestate nc se alege o valoare vk Sk-Ck se verific pentru vectorul (v1, v2, , vk) condiiile de continuare dac acestea sunt ndeplinite atunci xk = vk i k = k+1 else Ck k=k-1

Atunci cnd mulimile de valori posibile coincid S1=SS==Sn { void back() int k, i, s; s = 3; k = 1; for (i = 1; i <= n; i++) x[i] = 0; while (k > 0) { if (k == n + 1) { retsol(); k--; } else if (x[k] < s) { x[k]++; if (continuare(k)) k++; } else { x[k] = 0; k--; } }

PROBLEMA PERMUTRILOR
S se genereze toate permutrile unei mulimi de n numere (1, 2, , n). Explicaii: Funcia retsol este funcia de afiare a soluiilor. Cu o variabil nr contorizm numrul soluiilor iar cu ajutorul contorului i de la 1 la n afim soluiile. n funcia continuare nu avem dect o singur condiie, ca x[i] s fie diferit de x[k] (condiia combinrilor) pentru a nu se repeta soluiile. Funcia care stabilete soluiile rezultat i le reine n vectorul x[i] este back. Att timp ct se mai pot alege soluii posibile se verific dac nu s-a depit dimensiunea vectorului x[i] i se tiprete soluia, scznd i pasul de lucru cu o unitate. n caz contrar se verific dac mai sunt valori netestate nc i pentru acestea se verific condiiile problemei, apelnd funcia continuare. Dac condiiile sunt respectate valoarea devine soluie a problemei i se tiprete folosind apelul funciei retsol. n funcia principal se citete n care reprezint numrul de elemente ale mulimii iar la sfrit se apeleaz funcia back pentru a tipri soluiile. Exemplu: Fie n=3 adic mulimea {1, 2, 3}. Vor exista 6 variante de permutri : 123, 132, 213, 231, 312, 321

#include<iostream.h> #include<conio.h> #include<stdio.h> int x[10],n,nr = 1; void retsol() { int i ; printf("\nSolutia cu nr. %d este:", nr); for (i = 1; i <= n; i++) printf("%d", x[i]); nr++; } int cont(int k) { int i,t = 1; for (i = 1; i <= k - 1; i++) if (x[i] == x[k]) t = 0; return t; }

void back() { int k, i, s; k = 1;s = n; for (i = 1; i <= n; i++) x[i] = 0; while (k != 0) if (k == n + 1) { retsol(); k--; } else if (x[k] < s) { x[k]++; if (cont(k) == 1) k++; } else { x[k] = 0; k--; } } int main() { printf("n="); scanf("%d", &n); back(); return 0; }

SUBMULIMILE UNEI MULTIMI


Se citesc n i m numere naturale. S se genereze toate submulimile de ctre m elemente ale unei mulimi de n elemente (1, 2, , n), inclusiv mulimea vid. Explicaii: Funcia retsol este funcia de afiare a soluiilor. Vom contoriza soluiile cu variabila nr. Vom mai avea un contor m care dac este 0 se va afia soluia vid iar n caz contrar soluiile construite. n funcia cont avem condiia combinrilor pentru a nu se repeta soluiile. Funcia care stabilete soluiile rezultat i le reine n vectorul x[i] este back. Att timp ct se mai pot alege soluii posibile se verific dac nu s-a depit dimensiunea vectorului x[i] i se tiprete soluia, scznd i pasul de lucru cu o unitate. n caz contrar se verific dac mai sunt valori netestate nc i pentru acestea se verific condiiile problemei, apelnd funcia continuare. Dac condiiile sunt respectate valoarea devine soluie a problemei i se tiprete folosind apelul funciei retsol.

n funcia principal citim n - numrul de elemente ale mulimii. Cu ajutorul variabilei m, care pornete de la 0 la n, vom apela funcia back pentru a tipri soluiile rezultat.
Exemplu: Pentru mulimea {1, 2, 3} avem 8 submulimi: , {1}, {2}, {3}, {1,2}, {1, 3}, {2, 3}, {1, 2, 3}

#include<iostream.h> #include<stdio.h> #include<conio.h> int x[100],n,m,nr = 1; void retsol() { printf("\nSolutia cu nr %d : ", nr); if (m == 0) printf("0"); for (int i = 1; i <= m; i++) printf("%d ", x[i]); nr++; } int cont(int k) { int i,test = 1; for (i = 1; i <= k - 1; i++) if (x[i] >= x[k]) test = 0; return test; }

void back() { int i, k, s; k = 1; s = n; while (k != 0) if (k == m + 1) { retsol(); k--; } else if (x[k] < s) { x[k]++; if (cont(k) == 1) k++; } else { x[k] = 0; k--; } }

int main() {
printf("n="); scanf("%d", &n); for (m = 0; m <= n; m++) back(); return 0 ; }

PROBLEMA PERMUTRILOR LITERELOR UNUI CUVNT


Explicaii: Funcia retsol este funcia de afiare a soluiilor. Cu un contor i de la 1 la n vom afia cte o liter a cuvntului pe acelai rnd. Contorizarea soluiilor se va face cu ajutorul variabilei nr. n funcia continuare nu avem dect o singur condiie, ca x[i] s fie diferit de x[k] (condiia aranjamentelor) pentru a se verifica toate soluiile posibile. Funcia care stabilete soluiile rezultat i le reine n vectorul x[i] este back. Att timp ct se mai pot alege soluii posibile se verific dac nu s-a depit dimensiunea vectorului x[i] i se tiprete soluia, scznd i pasul de lucru cu o unitate. n caz contrar se verific dac mai sunt valori netestate nc i pentru acestea se verific condiiile problemei, apelnd funcia continuare. Dac condiiile sunt respectate valoarea devine soluie a problemei i se tiprete folosind apelul funciei retsol. n funcia principal se citete cuvntul, se reine n variabila n numrul de litere al acestuia i fiecare liter se va pstra n vectorul cuv[i]. La sfrit se apeleaz back pentru a tipri soluiile.

Exemplu: Vom considera un cuvnt format din patru litere: ALEX. n acest caz vom avea 24 de soluii: ALEX, ALXE, AELX, AEXL, AXLE, AXEL, LAEX, LAXE, LEAX, LEXA, LXAE, LXEA, EALX, EAXL, ELAX, ALXA, EXAL, EXLA, XALE, XAEL, XLAE, XLEA, XEAL, XELA.

#include<iostream.h> #include<stdio.h> #include<conio.h> #include<string.h> int n,x[15],nr = 1; char cuv[15]; void retsol() { printf("Solutia cu nr %d : ", nr); for (int i = 1; i <= n; i++) printf("%c ", cuv[x[i] - 1]); nr++; printf("\n");

} int cont(int k) { int i,test = 1; for (i = 1; i <= k - 1; i++) if (x[i] == x[k]) test = 0; return test; }

void back() { int k; k = 1; while (k > 0) if (k == n + 1) { retsol(); k--; } else if (x[k] < n) { x[k]++; if (cont(k) == 1) k++; } else { x[k] = 0; k--; } } int main() { printf("Cuvantul : "); scanf("%s", &cuv); n = strlen(cuv); back(); return 0; }

Rutina
n cazul variantei recursive rutina back se definete ca o funcie recursiv cu parametrul k (nivelul curent din stiv). Urcarea in stiv se face prin autoapelul funciei back cu o nou valoare pentru k. Generarea potenialilor candidai la soluie se face print-o instruciune for care parcurge valorile posibile de la limita inferioar la limita superioar. Iat soluia pentru problema permutarilor:

Implementarea codului
#include<iostream.h> #include<conio.h> int st[20],n; void tipar() { for(int i=1;i<=n;i++) cout<<st[i]<<' '; cout<<endl; } int valid ( int k ) { for ( int i=1;i<=k-1;i++) if (st[i]==st[k]) return 0; return 1; } void back ( int k ) { for ( int i=1;i<=n;i++ ) { st[k]=i; if ( valid ( k ) ) if ( k==n ) tipar(); else back(k+1); } } int main() { cout<<"n="; cin>>n; back(1); return 0; }

Plata unei sume de bani


Se dau suma S ce trebuie pltit i n tipuri de monede avnd valori de a1, a2, ... , an lei. Se cer toate modalitile de plat a sumei S utiliznd aceste monede. Observaii : valorile celor n monede se rein n vectorul a; se presupune c dispunem de attea monede din fiecare tip, cte sunt necesare ( acest numr se obine n ipoteza c toat sum a S este pltit numai cu monede de acel tip i se reine n vectorul b ); o soluie este sub forma unui vector cu n componente ( sol ) n care componenta i reine numrul de monede de tipul i care se folsesc pentru plata sumei S; acest numr poate fi i zero; toate componentele vectorului sol sunt iniializate cu 1 ( valoare aflat naintea valorilor posibile ); iniializarea unei componente se face i atunci cnd se revine la componenta de indice imediat inferior; funcia plata ( ) are doi parametrii : indicele componentei din sol care urmeaz a fi completat ( k ) i suma pltit pn n acel moment ( s0 ); apelul funciei plata ( ) ( din cadrul programului principal ) se face pentru prima component i suma 0; Fiind dat un nivel oarecare k, se procedeaz astfel :

atta timp ct este posibil s utilizm n plat nc o moned din tipul respectiv ( nu se depete suma care trebuie pltit ) :
se incrementeaz nivelul ( se folosete o nou moned de tipul k ); suma pltit se majoreaz cu valoarea acelei monede; n cazul cnd a fost obinut o soluie ( s0 = S ), aceasta se tiprete, contrar se apeleaz funcia pentru nivelul urmtor, cu noua valoare s0.

# include <iostream.h> # include <conio.h> int sol[10],a[10],b[10],n,i,s; void tipar ( int k ){ cout <<endl<<" SOLUTIE : "<<endl; for ( i=1;i<=k;i++ ) if ( sol[i] ) cout<<sol[i]<<" bancnote de "<<a[i]<<endl; } void plata ( int k,int s0 ) { while ( (sol[k]<b[k] )&&( s0+a[k]<=s ) ) { sol[k]=sol[k]+1; if(sol[k]>0) s0+=a[k]; if(s0==s) tipar(k); else if(k<n)plata(k+1,s0); } sol[k]=-1; } int main(){ cout<<"Cate tipuri de bancnote avem ? ";cin>>n; cout<<"Suma ce trebuie platita : ";cin>>s;

for(i=1;i<=n;i++){ cout<<"Valoarea monedei de tipul "<<i<<" : ";cin>>a [i]; b[i]=s/a[i]; sol[i]=-1; } plata(1,0); }
return 0;

Problema calului
Fiind dat o tabl de ah de dimensiunea nxn i un cal n colul stnga sus al acesteia, se cere s se afieze toate posibilitile de mutare a calului astfel nct s treac o singur dat prin fiecare ptrat al tablei.

#include<iostream.h> #include<fstream.h> long st[100][100],vec[20][20],i,n; int valid(int k) { if((st[k][1]<1) || (st[k][1]>n) || (st[k][2]<1) || (st[k][2]>n)) return 0; for(i=1;i<k;i++) if ((st[i][1]==st[k][1])&&(st[i][2]==st[k][2])) return 0; return 1;} int solutie(int k) {return (k==n*n);} void tipar(int k) {for(i=1;i<=k;i++) cout<<st[i][1]<<" "<<st[i][2]<<" "; cout<<endl<<endl;}

void bkt(int k) { int val; for(val=1;val<=8;val++) {st[k][1]=st[k-1][1]+vec[val][1]; st[k][2]=st[k-1][2]+vec[val][2]; if(valid(k)) {if(solutie(k)) tipar(k); else bkt(k+1); } } } int main() {int j; fstream f ("datee.in",ios::in); for(i=1;i<=8;i++) for(j=1;j<=2;j++) f>>vec[i][j]; cin>>n; st[1][1]=1; st[1][2]=1; bkt(2); return 0; }

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