Sunteți pe pagina 1din 17

5.

Metoda backtracking
5.1. Prezentare general
Pentru rezolvarea anumitor probleme este necesar desfurarea unui proces de cutare a soluiei aflate ntr-o anumit mulime, numit spaiul strilor. Pentru fiecare element din spaiul strilor este definit o mulime de aciuni sau alternative. Momentul iniial n rezolvarea problemei corespunde unei stri, numit stare iniial, iar soluiile corespund drumurilor in spaiul strilor, de la cea iniial pn la una final. Putem imagina procesul de rezolvare a problemei ca o secven de aciuni care asigur deplasarea (prin intermediul unei secvene de stri) n spaiul strilor din starea iniial la cea final. n cazul anumitor probleme se dorete obinerea unei singure soluii, altele solicit determinarea tuturor soluiilor sau determinarea unei soluii optime, dintr-un anumit punct de vedere (soluie optimal). Prin soluie a problemei se nelege o secven de aciuni care determin tranziia din starea iniial ntr-o stare final, fiecare component a unui drum soluie reprezentnd o alternativ din mulimea de variante posibile. Cu alte cuvinte, x0 este alternativa aleas pentru starea iniial, x1 este alternativa selectat pentru starea n care s-a ajuns pe baza opiunii x0 amd; dup efectuarea aciunii corespunztoare alegerii alternativei xn-1 rezult o stare final. Forma standard a acestei metode corespunde unei probleme n care trebuie gsit un drum soluie x=(x0, x1, ..., xn-1) cu xi Si, unde fiecare mulime Si este finit i conine si elemente. n plus se presupune c fiecare mulime Si este ordonat i reprezint mulimea alternativelor existente la momentul i al cutrii. n anumite cazuri intereseaz obinerea unei singure soluii, n altele sunt cutate toate soluiile problemei sau cele care ndeplinesc un criteriu dat (de exemplu, se maximizeaz sau minimizeaz o funcie f definit pe mulimea drumurilor soluie din spaiul strilor). Procesul de cutare a unui drum soluie revine la tentativa de extindere a poriunii de drum construit, alegnd prima alternativ disponibil pentru starea curent atins. Continuarea drumului poate fi realizat pn la atingerea unei stri finale sau pn la ntlnirea unei stri capcan (mulimea vid de alternative). Dac este atins o stare capcan, atunci este necesar revenirea la starea anterioar i selectarea urmtoarei alternative disponibile pentru aceast stare. Dac nu mai exist alternative disponibile, atunci se iniiaz o nou revenire amd. n cazul n care exist cel puin nc o alternativ disponibil, atunci se reia procesul de extindere a drumului rezultat. n condiiile n care revenirea poate conduce la atingerea strii iniiale i pentru ea nu mai exist alternative disponibile, se consider c problema nu are soluie. Pentru implementarea acestui tip de cutare este necesar reinerea alternativei selectate pentru fiecare stare atins pn la cea curent, astfel nct, n cazul unei reveniri aceasta s devin posibil alegerea alternativei urmtoare. Cu alte cuvinte, procesul de cutare revine la tentativa de extindere a drumului curent (pasul de continuare), cu eventuala revenire n cazul atingerii unei stri capcan (pasul de revenire - back), memornd alternativele selectate pentru fiecare stare intermediar atins (track). De aici i are geneza numele metodei backtracking. Pentru determinarea unei singure soluii, descrierea pe pai a metodei este: *0 starea iniial a problemei este stare curent i se consider prima alternativ posibil pentru starea curent ; fie aceasta x0 S0; *1 dac starea curent rezultat prin alternativa x0 este final, atunci x=(x0) este soluie; stop; *2 altfel, este selectat prima alternativ din mulimea de aciuni posibile pentru starea curent; fie aceasta x1 S1;

*3

dac secvena de alternative care a condus la starea curent este x=(x0, x1,..., xk), atunci: *4 dac starea curent este final, soluia este x=(x0, x1,..., xk); stop; *5 altfel *6 B1: dac pentru starea curent exist alternative disponibile, atunci se alege prima dintre ele i se continu; *7 B2: altfel, se revine la starea anterioar celei curente, soluia parial construit devine x=(x0, x1,..., xk-1) i se efectueaz B1. *8 dac, n urma unui pas de revenire s-a ajuns la starea iniial i nu mai sunt alternative disponibile, atunci problema nu are soluie; stop.

n cazul n care trebuie determinate toate soluiile problemei, cutarea continu dup determinarea fiecrei soluii prin efectuarea de reveniri succesive. Terminarea cutrii este decis n momentul n care s-a revenit la starea iniial i nu mai exist alternative disponibile. Dac se dorete obinerea numai a soluiilor care optimizeaz o funcie criteriu f, atunci metoda se aplic pentru determinarea tuturor soluiilor problemei, fiecare nou soluie rezultat fiind comparat cu cea mai bun soluie determinat anterior. Pentru aceasta este necesar reinerea celei mai bune soluii calculate pn la fiecare moment. Forma general a metodei backtracking este implementat de funcia back. void back(unsigned k) { if (k==n) retine_solutie(); else { x[k]=init(k); while (succ(k)) if (continuare(k)) back(k+1); } } n care: *9 retine_solutie este o funcie care descrie prelucrarea dorit pentru o soluie determinat (se afieaz rezultatul, se testeaz o funcie criteriu pentru soluia obinut amd); *10 init(k) efectueaz iniializarea lui xk cu o valoare prin care se indic faptul c, pn la acel moment, nu a fost selectat nici o alternativ pentru poziia k; *11 succ(k) este o funcie care calculeaz 1, dac i numai dac exist succesor pentru x k n Sk; *12 continuare(k) este o funcie pentru testarea condiiilor de continuare; calculeaz 1 dac i numai dac este posibil extinderea drumului curent.

5.2. Aplicaii
1. S se genereze toate permutrile mulimii {1, 2,..., n}. n acest caz, S0 = S2 = ... = Sn-1 = {1, 2,..., n}, alternativele posibile pentru starea iniial corespund alegerilor pentru prima poziie dintr-un vector soluie. Pentru fiecare k, 0 k < n 1 , dac x=(x0, x1,..., xk) este drumul calculat pn la momentul k, atunci x i x j , 0 i j k

i alternativele posibile pentru starea curent sunt elementele x k+1 din mulimea {1, 2,..., n} care ndeplinesc cerina xi x k +1 , 0 i k . De exemplu, pentru n=3, soluiile problemei sunt: x1=(1,2,3), x2=(1,3,2), x3=(2,1,3), x4=(2,3,1), x5=(3,1,2), x6=(3,2,1). Funcia init(k) realizeaz iniializarea elementului x[k] cu valoarea 0, pentru a marca faptul c, pn la momentul curent, nu a fost selectat nici o alternativ pentru x[k]. Funcia succ(k) calculeaz 1 dac elementul x[k] are succesor n mulimea {1, 2,..., n}, caz n care acesta este determinat prin incrementare. Altfel, funcia calculeaz 0. Funcia continuare(k) returneaz 1 dac i numai dac secvena (x0, x1,..., xk) calculat pn la momentul curent este corect, conform regulilor descrise anterior. Conform schemei generale, sursa C este, #include<stdio.h> #include<conio.h> unsigned x[7], n; unsigned init() { return 0; } unsigned succ(unsigned k) { return x[k]++<n; } unsigned continuare(unsigned k) { unsigned i; for(i=0;(i<k)&&(x[i]-x[k]);i++); return i==k; } void retine_solutie() { for (int i=0;i<n;i++) printf("%u ",x[i]); printf("\n"); getch(); } void back(unsigned k) { if(k==n) retine_solutie(); else { x[k]=init();

while(succ(k)) if(continuare(k))back(k+1); } } void main() { printf("Numarul de elemente ale permutarii:"); scanf("%u",&n); printf("Permutarile sunt \n"); back(0); } n cazul acestei probleme este posibil operarea unor simplificri n scrierea codului, pe baza observaiilor: - funcia init(k) nu depinde de valoarea lui k i returneaz ntotdeauna valoarea 0; - funcia succ(k) nu depinde de valoarea parametrului k i realizeaz ntotdeauna o incrementare (S0 = S1 = ... =Sn-1 = {1, 2,..., n}). Cu aceste remarci, funcia back(k) poate fi descris fr a utiliza funciile init i succ, astfel: void back(unsigned k) { unsigned i; if (k==n) retine_solutie(); else for (i=1;i<=n;i++) { x[k]=i; if (continuare(k))back(k+1); } } nlocuirea n procedura back a structurii repetitive while cu ciclul for este posibil datorit faptului c funcia succ realiza incrementarea valorii elementului x[k]. Varianta de surs C rezultat n urma acestor simplificri este: #include<stdio.h> #include<conio.h> unsigned x[7],n; unsigned continuare(unsigned k) { unsigned i; for(i=0;(i<k)&&(x[i]-x[k]);i++); return i==k;} void retine_solutie() {

for (int i=0;i<n;i++) printf("%u ",x[i]); printf("\n"); getch(); } void back(unsigned k) { unsigned i; if (k==n) retine_solutie(); else for (i=1;i<=n;i++) { x[k]=i; if (continuare(k))back(k+1); } } void main() { printf("Numarul de elemente ale permutarii:"); scanf("%u",&n); printf("Permutarile sunt \n"); back(0); } 2. S se scrie programul C pentru generarea tuturor submulimilor mulimii S={1, 2,..., n}, n 7. Vor fi generate succesiv toate submulimile cu k elemente, k=1, 2,, n. Fiecare submulime SubS este reprezentat prin funcia indicator, valorile acesteia fiind componentele vectorului SubS:

Condiiile de continuare corespund caracterizrii unei submulimi. Generarea unei soluii (submulime cu k elemente) este realizat cnd suma componentelor vectorului SubS este egal cu k. Fiecare submulime generat este memorat ntr-un vector de lungime 2n, care, n final, va reprezenta toate submulimile lui S (P({1, 2,..., n})). Sursa C este, #include <stdio.h> #include<conio.h> int n; long nr;

0,S[i] SubS SubS[i= ] 1, altfel

int x[10]; int tot[1024][10]; int suma(int t,int k) { int s,i; for(s=i=0;i<=t;i++)s+=x[i]; return s<=k; } int sumaf() { int s,i; for(s=i=0;i<n;i++)s+=x[i]; return s; } void back(int k,int t) { int i; if (t==n) if(sumaf()==k){ for(i=0;i<n;i++) tot[nr][i]=x[i]; nr++; } else ; else for(i=2;i>=1;i--) { x[t]=i-1; if(suma(t,k)) back(k,t+1); } } void main() { int k,j,dim; nr=0; printf("Dimensiunea multimii totale"); scanf("%i",&n); for(dim=1;dim<=n;dim++) back(dim,0); printf("Submultimile sunt:\n"); printf("Multimea \n"); for(k=0;k<nr;k++) {

for(j=0;j<n;j++) if (tot[k][j]) printf("%i ",j+1); printf("\n"); } printf("\nSunt %i submultimi",nr+1); getch(); } 3. S se genereze toate secvenele de cte p componente, dou cte dou distincte, din mulimea {1,2,..., n}, n 7, p n dat. Raionamenul pentru rezolvarea problemei este similar exemplului 1, cu meniunea c determinarea unei soluii are loc atunci cnd k devine p (s-a generat o secven de p elemente, dou cte dou distincte, din mulimea {1,2,..., n}). Sursa C este, #include<stdio.h> #include<conio.h> unsigned x[7],n,p; unsigned init() { return 0; } unsigned succ(unsigned k) { return x[k]++<n; } unsigned continuare(unsigned k) { unsigned i; for(i=0;(i<k)&&(x[i]-x[k]);i++); return i==k; } void retine_solutie() { for (int i=0;i<p;i++) printf("%u ",x[i]); printf("\n"); getch(); } void back(unsigned k) { if(k==p) retine_solutie();

else { x[k]=init(); while(succ(k)) if(continuare(k))back(k+1); } } void main() { printf("Numarul de elemente ale multimii:"); scanf("%u",&n); printf("Numarul de elemente ale secventelor:"); scanf("%u",&p); printf("Secventele sunt \n"); back(0); } 4. S se genereze toate configuraiilor n care 8 regine pot fi plasate pe o tabl de ah astfel nct s nu se atace reciproc (nici o pereche de regine nu trebuie plasat pe aceeai linie, coloan sau diagonal). Configuraiile sunt generate prin plasarea succesiv a reginelor n cte o linie a tablei; iniial tabla este liber. Deoarece pe fiecare linie i coloan a tablei de ah trebuie plasat o singur regin, configuraiile sunt reprezentate succesiv printr-un vector cu 8 componente conf. Valoarea componentei i din vectorul conf reprezint indicele coloanei n care este plasat regina aflat pe linia i. Din aceast reprezentare rezult c dou regine nu pot fi plasate pe aceeai linie a tablei de ah. Funcia is_ok(k) calculeaz valoarea 1 dac i numai dac, la adugarea celei de-a k regine, configuraia rezultat este corect, adic: - conf[k]<>conf[i], 0 i k 1 (reginele de pe liniile i i k sunt plasate pe coloane diferite) - conf[k ] conf[i ] k i (reginele de pe liniile i i k sunt plasate pe diagonale diferite). Funciaa regine implementeaz metoda backtracking pentru rezolvarea problemei. #include<stdio.h> #include<conio.h> #include<math.h> unsigned conf[8],nr=0,n; unsigned is_ok(unsigned k) { for(unsigned i=0;i<k;i++) if ((conf[k]==conf[i])|| (abs(conf[k]-conf[i])==abs(k-i))) return 0;

return 1; } void retine_solutie() { printf("Configuratie corecta:\n"); for(int i=0;i<n;i++){ printf("Regina %i se afla pe ",i+1); printf("Linia:%i si coloana%u\n",i+1,conf[i]); } printf("\n"); getch(); } void regine(unsigned i) { if(i==n){ retine_solutie (); nr++;} else for(unsigned k=1;k<n+1;k++){ conf[i]=k; if(is_ok(i)) regine(i+1); } } void main() { printf("Dimensiunea tablei pentru pozitionarea reginelor"); scanf("%u",&n); regine(0); printf("Sunt %u solutii ",nr); getch(); } 5. Fie o hart n ri, n 30. S se scrie programul care determin colorarea hrii cu m culori, m 7 , astfel nct oricare dou ri vecine s fie colorate diferit. Reprezentarea hrii se face printr-o tabel, A, cu

n n componente definite astfel:

Funcia verifica(k) returneaz valoarea 1 dac i numai dac colorarea primelor k ri respect condiia din enun. Funcia color implementeaz metoda backtracking aplicat pentru rezolvarea problemei.

1, tarile i , j sunt vecine . A[ i, j] = 0 , altfel

#include<stdio.h> #include<conio.h> typedef char cuvant[30]; unsigned A[30][30],sol[30],m,n; cuvant culoare[7]= {"alb","negru","rosu","albastru","gri","galben","verde"}; unsigned verifica(unsigned k) { for(int i=0;i<k;i++) if((sol[i]==sol[k])&&(A[i][k])) return 0; return 1; } void scrie() { printf("Colorare:\n"); for(int i=0;i<n;i++) printf("Tara %i are culoarea %s\n",i+1,culoare[sol[i]]); printf("\n"); getch(); } void color(unsigned k) { if(k==n) scrie(); else for(unsigned i=0;i<m;i++){ sol[k]=i; if(verifica(k)) color(k+1); } } void main() { printf("Numarul de tari:"); scanf("%u",&n); printf("Matricea vecinilor\n"); for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%u",&A[i][j]); printf("Numarul de culori:"); scanf("%u",&m); color(1); getch();

} 6. Se presupune c se dispune de n tipuri de bancnote, n 20, cu valori diferite; din fiecare tip se dispune de un numr cunoscut de bancnote. Considerndu-se dat o sum de bani s, s se determine o modalitatea de plat a sa utilizndu-se un numr minim de bancnote. Valorile i numrul de bancnote disponibile din fiecare tip sunt memorate ntr-o tabel y cu 2 linii i n coloane, astfel: pentru fiecare 0 i n -1, y[0][i] reprezint valoarea unei bancnote de tipul i i y[1][i] este numrul de bancnote disponibile din tipul i. Vectorul xb memoreaz modalitatea optim de plat a sumei s, adic xb[i] reprezint numrul de bancnote alese din tipul i ntr-o descompunere optim; vectorul x memoreaz descompunerea curent. Numrul minim de bancnote utilizate n plata sumei s este nrb. Metoda utilizat n rezolvarea problemei este backtracking, urmrindu-se minimizarea funciei f ( x ) = x[ i ] ,
i =0 n 1

condiiile

care

x[i ] y[0 ][i ] = s


i =0

n 1

0 x[i ] y[1][i ], i = 0 ,..., n 1 . Sunt generate toate descompunerile posibile ale sumei s

funcie de bancnotele disponibile i, la fiecare moment n care este determinat o astfel de descompunere, aceasta este comparat cu precedenta. n vectorul xb este memorat o cea mai bun descompunere pe baza criteriului f, dup fiecare astfel de comparaie. O surs C pentru rezolvarea problemei este, #include<stdio.h> #include<conio.h> long y[2][20],s; int n,nrb,x[100],xb[100]; int init() { return -1; } int urm(unsigned k) { return x[k]++<y[1][k]; } unsigned continuare(unsigned k) { long sc=0; for(int i=0;i<=k;i++) sc+=x[i]*y[0][i]; if(k<n-1) return sc<=s; return sc==s; } void retine_solutie()

{ int nr=0; for(int i=0;i<n;i++)nr+=x[i]; if(nr<nrb){ for (i=0;i<n;i++)xb[i]=x[i]; nrb=nr; } } void back(unsigned k) { if(k==n)retine_solutie(); else{ x[k]=init(); while (urm(k)) if(continuare(k))back(k+1); } } void main() { printf("Numarul bancnote:"); scanf("%i",&n); printf("Valorile si numarul exemplare\n"); for(int i=0;i<n;i++){ printf("Valoarea:"); scanf("%li",&y[0][i]); printf("Numarul de bancnote:"); scanf("%li",&y[1][i]); } printf("Suma schimbata:"); scanf("%li",&s); nrb=10000000; back(0); printf("Numarul minim de bancnote:%i\n",nrb); printf("Numarul de bancnote alese din fiecare tip\n"); for(i=0;i<n;i++) if(xb[i]) printf("De %li -> %i\n",y[0][i],xb[i]); getch(); } Pe baza unor observaii similare celor de la prima aplicaie, funcia back poate fi rescris astfel, void back(unsigned k) { if(k==n)retine_solutie();

else for(int i=0;i<=y[1][k];i++){ x[k]=i; if(continuare(k))back(k+1); } } 7. Se presupune c pe malul unui ru se afl o barc, trei misionari i trei canibali parial educai. Misionarii i canibalii doresc s traverseze rul, dar barca nu poate transporta dect cel mult dou persoane. Deoarece canibalii sunt numai parial educai, nu se poate avea ncredere n ei, aa c trebuie ca, n orice moment, pe cele dou maluri, numrul misionarilor s fie cel puin egal cu cel al canibalilor. S se scrie un program pentru rezolvarea problemei, indicndu-se, la fiecare moment, numrul misionarilor i al canibalilor pe fiecare dintre maluri i poziia brcii. #include<stdio.h> #include<conio.h> typedef struct{ int ncs,ncd,nms,nmd; /* numarul de canibali si misionari de pe malurile stang si drept ale raului*/ int pb; /* pozitia barcii*/ }stare; stare sol[50]; int mut[2][5]={{0,1,1,2,0},{1,0,1,0,2}}; /*(mut[0][i],mut[1][i])-o posibilitate corect de a alege mut[0][i] canibali i mut[1][i] misionari pentru a ndeplini condiia de non-atac la o mutare*/ FILE *f; // Funcia verific dac starea st a fost deja trecuta in vectorul solutie unsigned visit(stare st,int l) { // 1- starea st a fost trecuta anterior in solutie // 0- in caz contrar for(int i=0;i<l;i++) if ((sol[i].ncs==st.ncs) && (sol[i].ncd==st.ncd) && (sol[i].nmd==st.nmd) && (sol[i].nms==st.nms) && (sol[i].pb==st.pb)) return 1; return 0; }

// Funcia verific dac starea st este o stare valid (respect condiiile problemei) unsigned pot_muta(stare st, int j) { // 1- starea st poate fi acceptata // 0- in caz contrar if (st.pb==-1) // barca este pe malul stng if((st.ncs>=mut[0][j]) && // pot selecta mut[0][j] canibali i mut[1][j] misionari (st.nms>=mut[1][j])) return 1; if (st.pb==1) // barca este pe malul drept if((st.ncd>=mut[0][j])&& (st.nmd>=mut[1][j])) return 1; return 0; } void back(stare st, int l) { stare st1; int i,j; st=sol[l]; if((st.ncd+st.nmd==6)&&(st.pb==1)){ // o poziie valid for(i=0;i<=l;i++){ fprintf(f,"Mal st.: canibali="); fprintf(f,"%u",sol[i].ncs); fprintf(f,", misionari="); fprintf(f,"%u",sol[i].nms); fprintf(f," Mal dr.: canibali="); fprintf(f,"%u",sol[i].ncd); fprintf(f,", misionari="); fprintf(f,"%u",sol[i].nmd); fprintf(f," barca pe malul "); if (sol[i].pb==-1) fprintf(f,"stang\n"); else fprintf(f,"drept\n"); } fprintf(f,"\n"); } else for (j=0;j<5;j++) // pentru toate cele 5 posibiliti de alegere a unei mutri if(((st.ncs+st.pb*mut[0][j]<=st.nms+st.pb*mut[1][j]) || (st.nms+st.pb*mut[1][j]==0)) && // dac nr. canibali rmai pe malul stng<= nr. misionari rmai pe malul stng //sau nr. misionari rmai pe malul stng =0 ((st.ncd-st.pb*mut[0][j]<=st.nmd-st.pb*mut[1][j]) || (st.nmd-st.pb*mut[1][j]==0)) && (st.nms+st.pb*mut[1][j]>=0) &&

//dac nr. misionari rmai pe malul stng este nenegativ (st.ncs+st.pb*mut[0][j]>=0) && (st.nmd-st.pb*mut[1][j]>=0) && (st.ncd-st.pb*mut[0][j]>=0) && pot_muta(st,j)){ st1=st; st1.ncs+=st1.pb*mut[0][j]; st1.nms+=st1.pb*mut[1][j]; st1.nmd-=st1.pb*mut[1][j]; st1.ncd-=st1.pb*mut[0][j]; st1.pb=-st1.pb; if(!visit(st1,l)){ sol[l+1]=st1; back(st1,l+1); } } } void main() { f=fopen("canibali.txt","w"); sol[0].nms=3; sol[0].ncd=0; sol[0].ncs=3; sol[0].nmd=0; sol[0].pb=-1; back(sol[0],0); fclose(f); } Soluiile problemei calculate de program sunt: Mal stng Mal drept Poziie barc barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept

Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3

Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3 Mal st.: canibali=3 , misionari=3 Mal dr.: canibali=0 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=2 , misionari=3 Mal dr.: canibali=1 , misionari=0 Mal st.: canibali=0 , misionari=3 Mal dr.: canibali=3 , misionari=0 Mal st.: canibali=1 , misionari=3 Mal dr.: canibali=2 , misionari=0 Mal st.: canibali=1 , misionari=1 Mal dr.: canibali=2 , misionari=2 Mal st.: canibali=2 , misionari=2 Mal dr.: canibali=1 , misionari=1 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=3 , misionari=0 Mal dr.: canibali=0 , misionari=3 Mal st.: canibali=1 , misionari=0 Mal dr.: canibali=2 , misionari=3 Mal st.: canibali=2 , misionari=0 Mal dr.: canibali=1 , misionari=3 Mal st.: canibali=0 , misionari=0 Mal dr.: canibali=3 , misionari=3

barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept barca pe malul stang barca pe malul drept

5.3 Exerciii
1. Se presupune cunoscut funcia bijectiv g:{1,2,,n}{1,2,,n}. S se scrie programul care determin toate funciile bijective f:{1,2,,n}{1,2,,n}, cu proprietatea c fg=gf. 2. Se presupune cunoscut funcia bijectiv g:{1,2,,n}{1,2,,n}. S se scrie programul care determin toate funciile bijective f:{1,2,,n}{1,2,,n}, cu proprietatea c ff=g.

3. Fie a1, a2,,an o secven de numere reale. S se scrie programul pentru determinarea valorii maxime k i secvenele 1 i1<i2<<ik n, astfel nct ai1 < ai2 < ... < aik . 4. Fie A o tabel n n astfel nct A[i][j] 0, 0 i , j n 1 , reprezentnd cotele unui relief. Se presupune c n celula A[i0][j0] se toarn ap astfel nct se formeaz posibil mai multe rulee (funcie de diferenele de nivel). S se scrie un program care determin toate ruleele astfel formate. 5. Fie A o tabel n n astfel nct A[i][j] R, 0 i , j n 1 . Valorile pozitive din tabel reprezint recompense, iar cele negative reprezint amenzi. Celulele A[i][j] i A[k][p] sunt vecine dac i=k i j=p 1, sau j=p i i=k 1 0 i , j , k , p n 1 . S se scrie programul care determin o secven de celule vecine, avnd prima component A[0][0] i ultima A[n1][n-1], astfel nct suma valorilor celulelor secvenei s fie maxim. 6. S se scrie programul pentru determinarea numrului minim de culori necesar realizrii unei hri n care oricare dou ri vecine s fie colorate diferit. 7. Se consider o matrice A cu m linii i n coloane reprezentnd un labirint. Fiecare component A[i][j], 0 i m 1, 0 j n 1 semnific ieirile din camera (i,j), astfel: pentru fiecare dintre cele 4 direcii posibile (N, S, E, V) se reine 1, dac se poate iei spre acea direcie, altfel se memoreaz 0; irul binar NSEV este convertit n baza 10, valoarea fiind memorat n componenta corespunztoare camerei (i,j). Fie (i0,j0), 0 i0 m 1, 0 j0 n 1 o camer arbitrar din labirint. S se determine: a) toate variantele de ieire din labirint pornind din acea camer; b) cea mai scurt variant de ieire din labirint (cu trecere printr-un numr minim de camere). 8. Un comis-voiajor trebuie s viziteze n orae, etichetate cu numere de la 1 la n. Iniial acesta se afl n oraul etichetat cu 1. Comis-voiajorul dorete s revin n oraul din care a plecat, trecnd o singur dat prin toate celelalte orae. a) Cunoscndu-se legturile existente ntre orae, se cere determinarea tuturor drumurilor posibile pe care le poate efectua comis-voiajorul. b) Cunoscndu-se legturile existente ntre orae i costul deplasrii de la un ora la altul (n cazul n care deplasarea este posibil), se cere determinarea unui drum de cost minim.