Sunteți pe pagina 1din 8

Tehnici de programare prof.

Anca Barbulescu

BACKTRACKING
Se da ecuatia: x2+y2+z2=14 in multimea numerelor intregi. A rezolva aceasta ecuatie inseamna a gasi vectorii (x, y, z) din NxNxN care satisfac egalitatea data. Se stie ca patratul unui numar real (deci si natural) este intotdeauna pozitiv, deci termenii sumei sunt, fiecare, cuprinsi intre 0 si 14. 0 x2 14 si x N 0 x 3 x {0, 1, 2, 3} Analog se rationeaza pentru y, z si ajungem la concluzia ca solutiile, daca exista, sunt elemente ale produsului cartezian A1 x A2 x A3, unde A1 = A2 = A3 = {0, 1, 2, 3}. Pentru a ;e gasi se pot face incercari succesive, lucru posibil datorita numarului finit (in cazul nostru chiar mic) de elemente, posibile solutii. Vom urma tehnica stabilirii valorilor pentru x, y si verificarea posibilitatilor pentru z; daca nu se gaseste o solutie, atunci vom pastra valoarea lui x, dar o vom modifica pe a lui y. Dupa epuizarea tuturor variantelor lui y vom schimba si valoarea lui x si abia dupa terminarea tuturor valorilor posibile pentru x putem preciza cu exactitate cate si care sunt solutiile ecuatiei. 1. Etapa 1: avem fixata valorea x=0 si pentru ea cautam variante 1.1. Fixeaza y=0 si verifica posibilitatile pentru z z=0 x2+y2+z2=0+0+0=0 14 deci nu este solutie z=1 x2+y2+z2=0+0+1=1 14 ~ 2 2 2 z=2 x +y +z =0+0+4=4 14 ~ z=3 x2+y2+z2=0+0+9=9 14 ~ 1.2. Am epuizat valorile posibile pentru z, deci trecem la urmatoarea valoare pentru y si anume y=1 z=0 x2+y2+z2=0+1+0=1 14 deci nu este solutie z=1 x2+y2+z2=0+1+1=2 14 ~ 2 2 2 z=2 x +y +z =0+1+4=5 14 ~ z=3 x2+y2+z2=0+1+9=10 14 ~ 1.3. Nici la pasul 1.2. nu am gasit solutie; consideram valoarea posibila 2 pentru y z=0 x2+y2+z2=0+4+0=4 14 deci nu este solutie z=1 x2+y2+z2=0+4+1=5 14 ~ z=2 x2+y2+z2=0+4+4=8 14 ~ 2 2 2 z=3 x +y +z =0+4+9=13 14 ~ 1.4. Pentru valoarea fixata y=3 avem z=0 x2+y2+z2=0+9+0=9 14 deci nu este solutie z=1 x2+y2+z2=0+9+1=10 14 ~ z=2 x2+y2+z2=0+9+4=13 14 ~ 2 2 2 z=3 x +y +z =0+9+9=18 14 ~

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

Am epuizat toate variantele posibile pentru valoarea fixata x=0; trecem la etapa a urmatoare ce poate fi considerata luand urmatoarea valoare posibila pentru x. 2. Avem fixata valoarea x=1 2.1. Pentru y=0 avem variantele z=0 x2+y2+z2=1+0+0=1 14 deci nu este solutie z=1 x2+y2+z2=1+0+1=2 14 ~ 2 2 2 z=2 x +y +z =1+0+4=5 14 ~ z=3 x2+y2+z2=1+0+9=10 14 ~ 2.2. Fixam y=1 si variem z z=0 x2+y2+z2=1+1+0=2 14 deci nu este solutie z=1 x2+y2+z2=1+1+1=3 14 ~ z=2 x2+y2+z2=1+1+4=6 14 ~ 2 2 2 z=3 x +y +z =1+1+9=11 14 ~ 2.3. Schimbam din nou valoarea lui y si luam y=2 z=0 x2+y2+z2=1+4+0=5 14 deci nu este solutie z=1 x2+y2+z2=1+4+1=6 14 ~ 2 2 2 z=2 x +y +z =1+4+4=9 14 ~ z=3 x2+y2+z2=1+4+9=14 = 14 si am obtinut solutia (1, 2, 3) Pentru aflarea urmatoarele solutii se continua procedeul de cautare de mai sus: fixam valori posibile pentru primele si variem ultimele componente ale vectorului; cand nu mai sunt variante pentru acestea din urma ne intoarcem catre inceputul vectorului cu cate o pozitie, luand in consideratie urmatoarea valoare posibila. Deci, dupa cum se observa, solutia se construieste element cu element, prin punerea unor valori din cele posibile si verificarea conditiei de indeplinirea a egalitatii. Ca sa intelegem si sa automatizam acest mecanism, vom aseza intr-o stiva valorile pe care le incercam: pentru ca mai intai se fixeaza o valoare pentru x, apoi pentru y, iar z este cel care variaza cel mai repede, x va reprezenta primul nivel al stivei (primul element), y al doilea, iar z varful stivei (cand epuizam toate variantele pentru el il scoatem din stiva si modificam valoarea lui y). Deci, pentru etapa 1 de incercari valorile depuse in stiva se reprezinta astfel: 1.1. 1.2. 0 1 2 3 0 1 2 3 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1.3. 0 2 0 1.4. 0 3 0

1 2 0

2 2 0

3 2 0

1 3 0

2 3 0

3 3 0

A fost etapa in care pe nivelul 1 al stivei s-a mentinut 0 si, pe fiecare subetapa, s-a fixat cate o valoare pentru nivelul al doilea. Varful stivei si-a modificat valorile in permanenta,

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

iar trecerea de la o subetapa la urmatoarea consta in extragerea varfului, modificarea valorii pentru noul varf (nivelul 2) si adaugarea unui nou element posibil. Acelasi mecanism se urmeaza si in continuare. Etapele pana la gasirea primei solutii le reprezentam astfel: 2.1. 0 0 1 2.2. 0 1 1 2.3. 0 2 1

1 0 1

2 0 1

3 0 1

1 1 1

2 1 1

3 1 1

1 2 1

2 2 1

3 2 1

Sa caracterizam acum metoda backtracking. Este o metoda de programare conceputa pentru a rezolva probleme a caror solutie se poate reprezenta sub forma de vector. Mai exact, tipul de probleme pentru care se potriveste solicita determinarea unor valori (x1, x2, , xn) A1 x A2 x x An care sa indeplineasca anumite conditii, unde A1, A2, , An sunt multimi cu cardinal finit. Metoda backtracking este sigura din punct de vedere al gasirii solutiilor, atunci cand acestea exista, dar nu este eficienta din punct de vedere al spatiului de memorie si al timpului de calcul. Se bazeaza pe incercarea tuturor variantelor posibile si depistarea celor corecte, fapt pentru care se indica folosirea ei numai in situatiile in care nu se dispune de o alta metoda de rezolvare. Principiul de cautarea a unei solutii este urmatorul: se dau valori, pas cu pas, pentru componentele vectorului solutie; daca pentru o valoare aleasa nu se poate ajunge la solutie, atunci se renunta la acea valoare si se reia cautarea de la pasul anterior (cu o pozitie spre stanga). Algoritmul general al acestei metode, pentru aflarea unei solutii (x1, x2, , xn), poate fi descris astfel: 1. alegem o valoare oarecare pentru x1 2. cat timp sunt fixate valori pentru x1, , xk cautam o valoare posibila pentru xk+1 din Ak+1 si verificam daca se supune conditiilor problemei daca exista o asemenea valoare daca avem k+1 ultima componenta afisam solutia altfel aplicam metoda de completare pentru urmatoarea pozitie, considerand x1, , xk+1 fixate altfel reluam completarea lui xk, intorcandu-ne cu o pozitie si considerand completate x1, , xk-1 3. sfarsit Observam ca algoritmul testeaza toate variantele, deoarece se incheie atunci cand nu mai poate fi fixata nici o valoare pentru x1, adica putem spune ca am coborat in stiva pana cand aceasta s-a golit. La aplicarea acestei metode pentru o anumita problema, programatorul va trebui sa stabileasca urmatoarele: 1) cum se face alegerea primei valori pentru un element xk (care este criteriul de alegere a primei valori de pe nivelul k al stivei); 2) functia de testare a conditiilor problemei;

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

3) modul de afisare a solutiilor gasite; 4) functia pentru verificarea completitudinii unei solutii. Daca se opteaza pentru o implementare structurata, atunci se va folosi urmatorul algoritm: 1. k=1, dam o valoare lui x[k] 2. cat timp k>=0 (varful este cel putin pe nivelul 1) 2.1. repetam alegerea unei valori x[k] din Ak verificarea validitatii acesteia cat timp gasim valori in Ak, dar nu sunt valide 2.2. daca am gasit o valoare valida daca solutia este completa o afisam altfel trecem la completarea urmatorului nivel k=k+1 si x[k] ia o valoare initiala altfel ne intoarcem si refacem nivelul ultim din stiva k=k-1 3. sfarsit La rezolvarea ecuatiei x2+y2+z2=14, vom implementa urmatoarele functii: Initializarea, prin atribuirea valorii 1 pentru x[k] Alegerea unei valori pentru x[k] presupune inlocuirea valorii existente a lui x[k] cu urmatorul numar natural, dar care sa fie mai mic decat 3 Validarea valorii actuale a lui x[k] consta in verificarea inegalitatii x2+y2+z2<=14 Afisarea solutiei se realizeaza prin afisarea vectorului (x, y, z) Functia pentru testarea completitudinii solutiei contine verificarea identitatilor k=3 si x2+y2+z2=14 In functia principala se implementeaza algoritmul structurat pe care l-am dat anterior. Programul C este urmatorul:
#include <iostream.h> #include <conio.h> int x[10],i,k; int gaseste(int k) {if(x[k]<3) {x[k]++;return 1;} else return 0;} int valid(int k) { int s; for(i=1,s=0;i<=k;i++) s+=x[i]*x[i]; if(s<=14) return 1; else return 0;} int solutie(int k) {int s=0,sk=0; if(k==3) {s=1; for(i=1;i<=k;i++)sk+=x[i]*x[i];if(sk!=14) s=0;} return s;} void afis(int k) {cout << "\n"; for(i=1;i<=k;i++) cout << x[i] << " ";}

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

void main() {int g,v; clrscr(); cout << "\nDati termenul drept al ecuatiei: "; cin >> n; cout << "\nSolutiile ecuatiei x^2+y^2+z^2=14 sunt:\n"; k=1;x[k]=0; while(k) {do{g=gaseste(k);if(g) v=valid(k);}while(g && !v); if(g) if(solutie(k))afis(k); else {k++;x[k]=0;} else k--; } getch(); }

O generalizare a acestei probleme se enunta astfel: Sa se rezolve, in multimea numerelor naturale, ecuatia: x12+ +xn2=r Lasam pentru studiul individual scrierea algoritmului si implementarea programului. Singura observatie pe care o facem este referitoare la valorile posibile ce vor fi incercate de algoritm: acestea trebuie sa fie cuprinse intre 0 si [k], iar solutia completa trebuie sa aiba n componente ce verifica ecuatia.

PROBLEME REZOLVATE:
1. O problema mai simpla, dar asemanatoare cu aceasta este partitonarea unui numar natural n ca suma de k numere nenule. Prezentam direct algoritmul structurat, bazat pe cel general: 1. citim n, k 2. i=1, x[i]=0 3. cat timp i>0 3.1. repetam alegerea unei valori posibile x[i] verificarea validarii lui x[i] cat timp gasim x[i], dar nu e valid 3.2. daca avem x[i] valid daca solutia e completa o afisam altfel completam urmatoarea componenta i++ si x[i]=0 altfel refacem nivelul anterior i-4. sfarsit Functiile necesare sunt: Alegerea unei valori are ca argument pozitia i daca x[i]<n urmatoarea valoare este x[i]++ si se returneaza 1 altfel se returneaza 0 Validarea unei valori de pe pozitia i s=0 pentru j=1 la i actualizam s=s+x[j] daca s<=n se returneaza 1 altfel se returneaza 0

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

Completitudinea solutiei daca i==k atribuim c=1 altfel c=0 daca c==1 calculam s=0 pentru j=1 la i calculam s=s+x[j] daca s!=n actualizam c=0 se returneaza valoarea lui c Afisarea solutiei pentru i=1 la k afisam x[i] Programul C:
#include <iostream.h> #include <conio.h> int x[10],i,n,k; int gaseste(int i) {if(x[i]<n) {x[i]++;return 1;} else return 0;} int valid(int i) { int s; for(j=1,s=0;j<=i;j++) s+=x[j]; if(s<=n) return 1; else return 0;} int solutie(int i) {int s=0,sk=0; if(i==n) {s=1; for(j=1;j<=i;j++)sk+=x[j];if(sk!=n) s=0;} return s;} void afis(int i) {cout << "\n"; for(j=1;j<=i;j++) cout << x[j] << " ";} void main() {int g,v; clrscr(); cout << "\nDati numarul ce trebuie partitionat: "; cin >> n; cout << "\nDati numarul de partitii: "; cin >> k; cout << "\nDescompunerile lui " << n << ca suma de << k << termeni sunt: \n"; i=1;x[i]=0; while(i) {do{g=gaseste(i);if(g) v=valid(i);}while(g && !v); if(g) if(solutie(i))afis(i); else {i++;x[i]=0;} else i--; } getch(); }

Observatii: 1) Se poate impune ca termenii sumei sa fie numere distincte; atunci se va modifica validarea, adaugand conditia ca x[i] sa fie diferit de orice x[j] anterior.

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

2) Daca nu ne intereseaza ordinea aparitiei termenilor in suma, atunci se pot genera numai solutiile ale caror componente sunt asezate in ordine crescatoare. 2. Permutarile unei multimi Se stie de la matematica notiunea de multime si faptul ca elementele sale sunt unice (un element nu apare de doua ori in aceeasi multime). O metoda de reprezentare a unei multimi finite este enumerarea elementelor. In programare, o multime se reprezinta ca un vector, in care sunt enumerate elementele multimii respective. Datorita indicilor unui vector, apare o relatie de ordine, prin care fiecare componenta ocupa o anumita pozitie. Prin permutarile unei multimi se intelege formarea tuturor vectorilor cu elementele unei multimi, prin schimbarea ordinii acestora. Mai exact, generarea tuturor posibilitatilor de aranjare a n elemente ale unei multimi intr-un vector. Pentru ca intre orice multime A cu n elemente si multimea {1, 2, , n} putem construi bijectia care pune in corespondenta al I-lea element al multimii cu numarul I, convenim ca orice problema cu multimi sa o reducem la interpretarea ei in multimea {1,2,,n} , intelegand prin i al i-lea element al unei multimi date. Deci, generarea permutarilor unei multimi cu n elemente o vom realiza permutand in toate modurile numerele 1,2,,n, cu ajutorul metodei backtracking. O solutie consta intr-un vector de dimensiune n, ale carui elemente sunt numerele naturale de la 1 la n. Conditia ca o valoare sa fie valida este ca sa nu mai fi aparut pe pozitiile anterioare si, bineinteles, sa fie cuprinsa intre 1 si n. Alegerea unei valori o facem luand valoarea urmatoare celei deja alese. Afisarea este afisarea unui vector cu n elemente. Dam direct programul implementat in C:
#include <iostream.h> #include <conio.h> int k,x,v,n,s[10],h=0; char r; /*Functia de alegere a unei noi valori pentru x[k]*/ int aleg(int k) {if(s[k]<n){s[k]++;return 1;} else return 0; } /*Functia de validare a valorii lui x[k]*/ int validez(int k) {int i,v=1; for(i=1;i<k;i++) if(s[k]==s[i])v=0; return v; } /*Functia de afisare a vectorului solutie*/ void afis() {int i; for(i=1;i<=n;i++) cout << s[i] << " "; cout << "\t"; }

Colegiul National Gheorghe Titeica

Tehnici de programare prof. Anca Barbulescu

/*Functia principala*/ void main() {cout << "\nDati n: "; cin >> n; k=1;s[k]=0; while(k>0) {do{x=aleg(k); if(x) v=validez(k);}while(x && !v); if(x) if(k==n){afis();h++;getch();} else {k++;s[k]=0;} else k--; } cout << "\nExista " << h << " posibilitati de permutare!"; r=getch(); }

3. Aranjamente de n luate cate k Problema aranjamentelor cere generarea tuturor vectorilor de dimensiune k, cu cele n elemente ale unei multimi. Ca si la permutari, vom genera multimile cu k elemente numere naturale cuprinse intre 1 si n, folosind aceeasi metoda backtracking. De data aceasta, solutia este completa daca are exact k elemente distincte, cuprinse intre 1 si n 4. Combinari de n luate cate k 5. Produsul cartezian al mai multor multimi

Colegiul National Gheorghe Titeica

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