5.

Metoda backtracking
5.1. Prezentare generală
Pentru rezolvarea anumitor probleme este necesară desfăşurarea unui proces de căutare a soluţiei aflate într-o anumită mulţime, numită spaţiul stărilor. Pentru fiecare element din spaţiul stărilor este definită o mulţime de acţiuni sau alternative. Momentul iniţial în rezolvarea problemei corespunde unei stări, numită stare iniţială, iar soluţiile corespund drumurilor in spaţiul stărilor, de la cea iniţială până la una finală. Putem imagina procesul de rezolvare a problemei ca o secvenţă de acţiuni care asigură “deplasarea” (prin intermediul unei secvenţe de stări) în spaţiul stărilor din starea iniţială la cea finală. În cazul anumitor probleme se doreşte obţinerea unei singure soluţii, altele solicită determinarea tuturor soluţiilor sau determinarea unei soluţii optime, dintr-un anumit punct de vedere (soluţie optimală). Prin soluţie a problemei se înţelege o secvenţă de acţiuni care determină tranziţia din starea iniţială într-o stare finală, fiecare componentă a unui drum soluţie reprezentând o alternativă din mulţimea de variante posibile. Cu alte cuvinte, x0 este alternativa aleasă pentru starea iniţială, x1 este alternativa selectată pentru starea în care s-a ajuns pe baza opţiunii x0 şamd; după efectuarea acţiunii corespunzătoare alegerii alternativei xn-1 rezultă o stare finală. Forma standard a acestei metode corespunde unei probleme în care trebuie găsit un drum soluţie x=(x0, x1, ..., xn-1) cu xi ∈ Si, unde fiecare mulţime Si este finită şi conţine si elemente. În plus se presupune că fiecare mulţime Si este ordonată şi reprezintă mulţimea alternativelor existente la momentul i al căutării. În anumite cazuri interesează obţinerea unei singure soluţii, în altele sunt căutate toate soluţiile problemei sau cele care îndeplinesc un criteriu dat (de exemplu, se maximizează sau minimizează o funcţie f definită pe mulţimea drumurilor soluţie din spaţiul stărilor). Procesul de căutare a unui drum soluţie revine la tentativa de extindere a porţiunii de drum construit, alegând prima alternativă disponibilă pentru starea curentă atinsă. Continuarea drumului poate fi realizată până la atingerea unei stări finale sau până la întâlnirea unei stări capcană (mulţimea vidă de alternative). Dacă este atinsă o stare capcană, atunci este necesară revenirea la starea anterioară şi selectarea următoarei alternative disponibile pentru această stare. Dacă nu mai există alternative disponibile, atunci se iniţiază o nouă revenire şamd. În cazul în care există cel puţin încă o alternativă disponibilă, atunci se reia procesul de extindere a drumului rezultat. În condiţiile în care revenirea poate conduce la atingerea stării iniţiale şi pentru ea nu mai există alternative disponibile, se consideră că problema nu are soluţie. Pentru implementarea acestui tip de căutare este necesară reţinerea alternativei selectate pentru fiecare stare atinsă până la cea curentă, astfel încât, în cazul unei reveniri aceasta să devină posibilă alegerea alternativei următoare. Cu alte cuvinte, procesul de căutare revine la tentativa de extindere a drumului curent (pasul de continuare), cu eventuala revenire în cazul atingerii unei stări capcană (pasul de revenire - back), memorând alternativele selectate pentru fiecare stare intermediară atinsă (track). De aici îşi are geneza numele metodei backtracking. Pentru determinarea unei singure soluţii, descrierea pe paşi a metodei este: *0 starea iniţială 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 soluţie; stop; *2 altfel, este selectată prima alternativă din mulţimea de acţiuni posibile pentru starea curentă; fie aceasta x1 ∈ S1;

. xk)... *12 continuare(k) este o funcţie pentru testarea condiţiilor de continuare. fiecare nouă soluţie rezultată fiind comparată cu “cea mai bună” soluţie determinată anterior. Să se genereze toate permutările mulţimii {1. 0 ≤ k < n − 1 . *11 succ(k) este o funcţie care calculează 1. void back(unsigned k) { if (k==n) retine_solutie(). x1. else { x[k]=init(k). xk-1) şi se efectuează B1. S0 = S2 = . calculează 1 dacă şi numai dacă este posibilă extinderea drumului curent. ∀0 ≤ i ≠ j ≤ k . alternativele posibile pentru starea iniţială corespund alegerilor pentru prima poziţie dintr-un vector soluţie. x1.. } } în care: *9 retine_solutie este o funcţie care descrie prelucrarea dorită pentru o soluţie determinată (se afişează rezultatul. se revine la starea anterioară celei curente.. atunci problema nu are soluţie. Terminarea căutării este decisă în momentul în care s-a revenit la starea iniţială şi nu mai există alternative disponibile.2.. while (succ(k)) if (continuare(k)) back(k+1).. nu a fost selectată nici o alternativă pentru poziţia k.. x1. = Sn-1 = {1... atunci x i ≠ x j .. În cazul în care trebuie determinate toate soluţiile problemei. Pentru fiecare k... *8 dacă. atunci metoda se aplică pentru determinarea tuturor soluţiilor problemei. n}. 2.*3 dacă secvenţa de alternative care a condus la starea curentă este x=(x0. xk) este drumul calculat până la momentul k... xk). stop. atunci se alege prima dintre ele şi se continuă. *7 B2: altfel. până la acel moment.. 2... Aplicaţii 1. Pentru aceasta este necesară reţinerea “celei mai bune” soluţii calculate până la fiecare moment.. 5. x1.. căutarea continuă după determinarea fiecărei soluţii prin efectuarea de reveniri succesive. În acest caz. Dacă se doreşte obţinerea numai a soluţiilor care optimizează o funcţie criteriu f. dacă x=(x0. în urma unui pas de revenire s-a ajuns la starea iniţială şi nu mai sunt alternative disponibile. soluţia parţial construită devine x=(x0. soluţia este x=(x0. stop.. *5 altfel *6 B1: dacă pentru starea curentă există alternative disponibile. *10 init(k) efectuează iniţializarea lui xk cu o valoare prin care se indică faptul că... n}. Forma generală a metodei backtracking este implementată de funcţia back.. dacă şi numai dacă există succesor pentru x k în Sk. atunci: *4 dacă starea curentă este finală. se testează o funcţie criteriu pentru soluţia obţinută şamd)...

printf("\n").1). nu a fost selectată nici o alternativă pentru x[k]. soluţiile problemei sunt: x1=(1. pentru n=3.. } void back(unsigned k) { if(k==n) retine_solutie(). } void retine_solutie() { for (int i=0. #include<stdio..h> unsigned x[7]. Funcţia continuare(k) returnează 1 dacă şi numai dacă secvenţa (x0. caz în care acesta este determinat prin incrementare. n.h> #include<conio.3. return i==k.şi alternativele posibile pentru starea curentă sunt elementele x k+1 din mulţimea {1.1.2).. x2=(1. conform regulilor descrise anterior.i++) printf("%u ". pentru a marca faptul că. unsigned init() { return 0.3. ...2.. ∀0 ≤ i ≤ k .1.3).x[i]).. x4=(2. n} care îndeplinesc cerinţa xi ≠ x k +1 . x1.(i<k)&&(x[i]-x[k]). De exemplu. până la momentul curent.1)... funcţia calculează 0... x3=(2. x6=(3. } unsigned succ(unsigned k) { return x[k]++<n. sursa C este. else { x[k]=init(). xk) calculată până la momentul curent este corectă.3).i++). Conform schemei generale. 2. Funcţia init(k) realizează iniţializarea elementului x[k] cu valoarea 0. Funcţia succ(k) calculează 1 dacă elementul x[k] are succesor în mulţimea {1.. n}.2). } unsigned continuare(unsigned k) { unsigned i. 2. Altfel.2. for(i=0. x5=(3. getch().i<n.

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

getch().i++) printf("%u ". va reprezenta toate submulţimile lui S (P({1.S[i]∉ SubS SubS[i= ]  1. altfel .. } 2. } void back(unsigned k) { unsigned i.…. n})). else for (i=1. în final.. printf("Permutarile sunt \n"). Fiecare submulţime generată este memorată într-un vector de lungime 2n.i++) { x[k]=i. #include <stdio. scanf("%u". Generarea unei soluţii (submulţime cu k elemente) este realizată când suma componentelor vectorului SubS este egală cu k. 2.i<=n. n ≤ 7. k=1. Fiecare submulţime SubS este reprezentată prin funcţia indicator. Sursa C este.for (int i=0.&n). n..i<n.x[i]).  0.. if (k==n) retine_solutie(). long nr. 2. if (continuare(k))back(k+1). valorile acesteia fiind componentele vectorului SubS: Condiţiile de continuare corespund caracterizării unei submulţimi.h> #include<conio. back(0)... n}. printf("\n"). Vor fi generate succesiv toate submulţimile cu k elemente. } } void main() { printf("Numarul de elemente ale permutarii:")... 2. Să se scrie programul C pentru generarea tuturor submulţimilor mulţimii S={1. care.h> int n.

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

j++) if (tot[k][j]) printf("%i ".i++) printf("%u ". } unsigned continuare(unsigned k) { unsigned i. unsigned init() { return 0. Să se genereze toate secvenţele de câte p componente.. din mulţimea {1. getch(). printf("\n"). n}..(i<k)&&(x[i]-x[k])..n. Sursa C este.for(j=0. printf("\n")..i++). } unsigned succ(unsigned k) { return x[k]++<n. } 3.2. #include<stdio. return i==k. } printf("\nSunt %i submultimi". } void back(unsigned k) { if(k==p) retine_solutie().. Raţionamenul pentru rezolvarea problemei este similar exemplului 1.x[i])..nr+1).. două câte două distincte. cu menţiunea că determinarea unei soluţii are loc atunci când k devine p (s-a generat o secvenţă de p elemente. p≤ n dat. } void retine_solutie() { for (int i=0.2. for(i=0.j+1).h> #include<conio.p.j<n.i<p. . n}). n ≤ 7. din mulţimea {1. getch()..h> unsigned x[7]. două câte două distincte.

} 4. back(0). #include<stdio. Valoarea componentei i din vectorul conf reprezintă indicele coloanei în care este plasată regina aflată pe linia i. iniţial tabla este liberă. coloană sau diagonală). Să se genereze toate configuraţiilor în care 8 regine pot fi plasate pe o tablă de şah astfel încât să nu se atace reciproc (nici o pereche de regine nu trebuie plasată pe aceeaşi linie. la adăugarea celei de-a k regine. Funcţia is_ok(k) calculează valoarea 1 dacă şi numai dacă. scanf("%u".else { x[k]=init().h> #include<conio. 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).i++) if ((conf[k]==conf[i])|| (abs(conf[k]-conf[i])==abs(k-i))) return 0.&n). unsigned is_ok(unsigned k) { for(unsigned i=0.nr=0.&p). printf("Numarul de elemente ale secventelor:"). scanf("%u". Funcţiaa regine implementează metoda backtracking pentru rezolvarea problemei.h> #include<math. configuraţiile sunt reprezentate succesiv printr-un vector cu 8 componente conf.conf[k]<>conf[i].h> unsigned conf[8]. . Configuraţiile sunt generate prin plasarea succesivă a reginelor în câte o linie a tablei. adică: .i<k. printf("Secventele sunt \n"). while(succ(k)) if(continuare(k))back(k+1). Din această reprezentare rezultă că două regine nu pot fi plasate pe aceeaşi linie a tablei de şah. configuraţia rezultată este corectă. Deoarece pe fiecare linie şi coloană a tablei de şah trebuie plasată o singură regină.n. } } void main() { printf("Numarul de elemente ale multimii:").

scanf("%u".conf[i]). astfel încât oricare două ţări vecine să fie colorate diferit.i<n.k<n+1. Să se scrie programul care determină colorarea hărţii cu m culori. Reprezentarea hărţii se face printr-o tabelă.} else for(unsigned k=1.return 1. getch(). getch(). Funcţia color implementează metoda backtracking aplicată pentru rezolvarea problemei. j] =   0 . nr++. j sunt vecine . regine(0). tarile i . } } void main() { printf("Dimensiunea tablei pentru pozitionarea reginelor"). A. } void regine(unsigned i) { if(i==n){ retine_solutie ().i++){ printf("Regina %i se afla pe ". for(int i=0. } printf("\n"). } void retine_solutie() { printf("Configuratie corecta:\n"). if(is_ok(i)) regine(i+1).k++){ conf[i]=k.nr). m ≤ 7 . altfel . printf("Linia:%i si coloana%u\n". Fie o hartă n ţări.  1. A[ i.&n).i+1). n ≤ 30. } 5. printf("Sunt %u solutii ". cu n × n componente definite astfel: Funcţia verifica(k) returnează valoarea 1 dacă şi numai dacă colorarea primelor k ţări respectă condiţia din enunţ.i+1.

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

din fiecare tip se dispune de un număr cunoscut de bancnote.i<=k.nrb. În vectorul xb este memorată o cea mai bună descompunere pe baza criteriului f. O sursă C pentru rezolvarea problemei este. n ≤ 20. Considerându-se dată o sumă de bani s. Numărul minim de bancnote utilizate în plata sumei s este nrb..} 6. după fiecare astfel de comparaţie. i = 0 .. i =0 n −1 în condiţiile în care ∑ x[i ] y[0 ][i ] = s i =0 n −1 şi 0 ≤ x[i ] ≤ y[1][i ]. for(int i=0. să se determine o modalitatea de plată a sa utilizându-se un număr minim de bancnote. return sc==s. #include<stdio. } unsigned continuare(unsigned k) { long sc=0. Sunt generate toate descompunerile posibile ale sumei s funcţie de bancnotele disponibile şi. if(k<n-1) return sc<=s. aceasta este comparată cu precedenta. adică xb[i] reprezintă numărul de bancnote alese din tipul i într-o descompunere optimă.xb[100]. cu valori diferite. la fiecare moment în care este determinată o astfel de descompunere.. n −1 . } void retine_solutie() . Se presupune că se dispune de n tipuri de bancnote. int n.x[100]. vectorul x memorează descompunerea curentă. urmărindu-se minimizarea funcţiei f ( x ) = ∑ x[ i ] .h> long y[2][20]. Valorile şi numărul de bancnote disponibile din fiecare tip sunt memorate într-o tabelă y cu 2 linii şi n coloane. Metoda utilizată în rezolvarea problemei este backtracking. int init() { return -1.i++) sc+=x[i]*y[0][i].s.h> #include<conio. y[0][i] reprezintă valoarea unei bancnote de tipul i şi y[1][i] este numărul de bancnote disponibile din tipul i. astfel: pentru fiecare 0 ≤ i ≤ n -1.. } int urm(unsigned k) { return x[k]++<y[1][k]. Vectorul xb memorează modalitatea optimă de plată a sumei s.

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

1. int mut[2][5]={{0. Deoarece canibalii sunt numai “parţial educaţi”.h> #include<conio. /*(mut[0][i]. aşa că trebuie ca. trei misionari şi trei canibali “parţial educaţi“.h> typedef struct{ int ncs. în orice moment.nms==st. la fiecare moment. // Funcţia verifică dacă starea st a fost deja trecuta in vectorul solutie unsigned visit(stare st.nmd) && (sol[i].i++) if ((sol[i].nmd. dar barca nu poate transporta decât cel mult două persoane.2.2}}. if(continuare(k))back(k+1). /* numarul de canibali si misionari de pe malurile stang si drept ale raului*/ int pb. pe cele două maluri.{1. Se presupune că pe malul unui râu se află o barcă.0.in caz contrar for(int i=0.1.0}.1. #include<stdio.i++){ x[k]=i.starea st a fost trecuta anterior in solutie // 0. } } 7.ncs) && (sol[i]. indicându-se. Să se scrie un program pentru rezolvarea problemei.i<=y[1][k]. return 0.ncd. numărul misionarilor să fie cel puţin egal cu cel al canibalilor.nmd==st.i<l.mut[1][i])-o posibilitate corectă de a alege mut[0][i] canibali şi mut[1][i] misionari pentru a îndeplini condiţia de non-atac la o mutare*/ FILE *f. } .int l) { // 1. Misionarii şi canibalii doresc să traverseze râul.pb)) return 1.else for(int i=0. nu se poate avea încredere în ei.ncd==st.ncd) && (sol[i].nms. /* pozitia barcii*/ }stare. numărul misionarilor şi al canibalilor pe fiecare dintre maluri şi poziţia bărcii.pb==st.ncs==st.nms) && (sol[i]. stare sol[50].0.

"%u"." barca pe malul ").sol[i].nmd).pb*mut[1][j]>=0) && .ncs>=mut[0][j]) && // pot selecta mut[0][j] canibali şi mut[1][j] misionari (st.in caz contrar if (st. int l) { stare st1."\n").pb==-1) // barca este pe malul stâng if((st.pb==1) // barca este pe malul drept if((st.ncd-st.nms). else fprintf(f.pb==-1) fprintf(f. } void back(stare st.ncs). fprintf(f. fprintf(f. } fprintf(f. } else for (j=0. canibali rămaşi pe malul stâng<= nr.pb*mut[0][j]<=st. if (sol[i]."%u". fprintf(f. fprintf(f.sol[i].pb*mut[1][j]) || (st.: canibali="). if (st."stang\n").nmd-st.nmd==6)&&(st.nmd>=mut[1][j])) return 1.pb*mut[0][j]<=st. fprintf(f.nms+st. misionari rămaşi pe malul stâng //sau nr.i++){ fprintf(f.pb==1)){ // o poziţie validă for(i=0. if((st."Mal st. st=sol[l].nms>=mut[1][j])) return 1.nms+st.i<=l.pb*mut[1][j]) || (st.sol[i].nmd-st. fprintf(f. int j) { // 1.". int i.starea st poate fi acceptata // 0.pb*mut[1][j]==0)) && // dacă nr.// Funcţia verifică dacă starea st este o stare validă (respectă condiţiile problemei) unsigned pot_muta(stare st.pb*mut[1][j]==0)) && (st. return 0.".j++) // pentru toate cele 5 posibilităţi de alegere a unei mutări if(((st. misionari rămaşi pe malul stâng =0 ((st."%u"." Mal dr.ncd).ncd+st.nms+st.j. misionari=").ncs+st. fprintf(f.j<5."drept\n").ncd>=mut[0][j])&& (st."%u". fprintf(f. misionari=").sol[i].: canibali=").

misionari=0 Mal dr. misionari=1 Mal dr.ncs+=st1.l)){ sol[l+1]=st1.ncd-st.nms+=st1. misionari=0 Mal dr. misionari=0 Mal dr.: canibali=3 .pb*mut[1][j]>=0) && (st.pb=-st1. misionari=2 Mal st. st1.nms=3. sol[0].: canibali=3 .: canibali=1 . } } } void main() { f=fopen("canibali.pb*mut[1][j].: canibali=0 .pb*mut[0][j].: canibali=1 .pb*mut[1][j]. misionari=1 Mal dr. misionari=3 Mal dr. misionari=2 Mal st.: canibali=2 .: canibali=0 .: canibali=0 . misionari=3 Mal st. misionari=0 Mal st.ncs+st. st1.pb*mut[0][j]>=0) && (st.: canibali=1 .: canibali=2 .pb. misionari=3 Mal dr.: canibali=2 .ncd=0. st1.: canibali=0 .ncd-=st1. misionari=1 Mal st. misionari=3 . misionari=0 Mal st.nmd-st.txt". misionari=0 Mal st. sol[0].0). misionari=0 Mal st. misionari=2 Mal dr.: canibali=2 .pb=-1.nmd=0. misionari rămaşi pe malul stâng este nenegativ (st."w"). sol[0].: canibali=1 .: canibali=2 . misionari=1 Mal st.: canibali=1 .: canibali=1 . misionari=0 Mal dr.: canibali=1 .: canibali=3 . misionari=3 Mal dr.pb*mut[0][j].: canibali=3 . misionari=2 Mal dr. sol[0].nmd-=st1. back(st1. st1. } Soluţiile problemei calculate de program sunt: Mal stâng Mal drept Poziţie 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.j)){ st1=st. fclose(f). misionari=3 Mal dr. if(!visit(st1.//dacă nr. misionari=3 Mal st. misionari=3 Mal st.: canibali=2 .pb*mut[0][j]>=0) && pot_muta(st. st1.: canibali=1 .l+1). sol[0]. back(sol[0].: canibali=2 .ncs=3.: canibali=2 .

misionari=3 Mal dr. misionari=0 Mal st. misionari=0 Mal st.: canibali=0 . misionari=0 Mal dr.: canibali=2 . misionari=0 Mal st.: canibali=0 .n}→{1. Se presupune cunoscută funcţia bijectivă g:{1. misionari=2 Mal dr. misionari=0 Mal dr.: canibali=1 . misionari=0 Mal st. misionari=0 Mal dr.: canibali=2 .: canibali=2 . misionari=3 Mal st.: canibali=1 .: canibali=1 . misionari=0 Mal dr.: canibali=1 . misionari=3 Mal st.2.: canibali=2 . misionari=1 Mal dr.: canibali=3 .…. misionari=0 Mal dr.: canibali=1 . 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. misionari=3 Mal st. misionari=0 Mal st. misionari=3 Mal dr.: canibali=0 .: canibali=2 . misionari=3 Mal st.: canibali=1 . cu proprietatea că f○f=g.: canibali=3 . .: canibali=2 .: canibali=0 . misionari=0 Mal st.: canibali=2 .: canibali=0 .: canibali=2 .: canibali=2 . misionari=3 Mal dr. misionari=2 Mal dr.2. misionari=0 Mal st. misionari=3 Mal st. misionari=3 Mal dr.….: canibali=1 . misionari=0 Mal dr. Să se scrie programul care determină toate funcţiile bijective f:{1.: canibali=1 . misionari=3 Mal st. misionari=2 Mal st.…. misionari=1 Mal st. misionari=3 Mal dr.: canibali=1 .n}.: canibali=0 . cu proprietatea că f○g=g○f. misionari=3 Mal st. misionari=1 Mal st.: canibali=2 .: canibali=1 . misionari=0 Mal dr.: canibali=0 .n}→{1.2. misionari=3 Mal dr.: canibali=1 . misionari=1 Mal dr. misionari=3 Mal dr.: canibali=0 . misionari=2 Mal st. misionari=0 Mal st. misionari=3 Mal dr. misionari=0 Mal dr. misionari=0 Mal dr.: canibali=1 .: canibali=1 .: canibali=3 .: canibali=1 .: canibali=3 . Se presupune cunoscută funcţia bijectivă g:{1.: canibali=2 . misionari=0 Mal st. misionari=0 Mal dr. Să se scrie programul care determină toate funcţiile bijective f:{1. misionari=1 Mal dr. misionari=3 Mal st.: canibali=2 . misionari=3 Mal dr.2.: canibali=1 .: canibali=2 .: canibali=1 .…. misionari=3 Mal st. misionari=3 Mal dr.: canibali=1 .….: canibali=2 . misionari=3 Mal st.3 Exerciţii 1. misionari=3 Mal dr.: canibali=2 .: canibali=0 . misionari=0 Mal st.: canibali=2 . misionari=0 Mal st.: canibali=2 . misionari=2 Mal st.: canibali=3 .: canibali=1 .: canibali=1 .: canibali=1 . misionari=2 Mal dr.…. misionari=3 Mal st. misionari=0 Mal st. misionari=0 Mal dr.n}→{1.2.: canibali=0 . misionari=3 Mal st.….2.: canibali=1 . misionari=3 Mal dr.: canibali=2 .: canibali=3 .2. misionari=1 Mal dr.: canibali=3 . misionari=1 Mal st.: canibali=1 .….: canibali=2 . misionari=3 Mal dr.: canibali=3 .n}. misionari=0 Mal st.: canibali=3 .: canibali=1 .: canibali=3 .: canibali=2 .: canibali=0 .: canibali=0 .: canibali=2 .Mal st. misionari=0 Mal st.: canibali=2 . misionari=2 Mal dr.: canibali=3 .n}→{1.n}. misionari=0 Mal dr.: canibali=3 . misionari=2 Mal st.2.: canibali=2 . misionari=3 Mal dr.: canibali=1 . misionari=3 Mal st.: canibali=2 . 2. misionari=0 Mal dr.n}. misionari=1 Mal st. misionari=0 Mal dr.

a) Cunoscându-se legăturile existente între oraşe. altfel se memorează 0.an o secvenţă de numere reale. Fiecare componentă A[i][j]. Să se determine: a) toate variantele de ieşire din labirint pornind din acea cameră.j0). dacă se poate ieşi spre acea direcţie. 7. Celulele A[i][j] şi A[k][p] sunt vecine dacă i=k şi j=p ± 1. Fie A o tabelă n × n astfel încât A[i][j] ∈ R. b) cea mai scurtă variantă de ieşire din labirint (cu trecere printr-un număr minim de camere). j . astfel: pentru fiecare dintre cele 4 direcţii posibile (N. reprezentând cotele unui relief. se cere determinarea unui drum de cost minim. b) Cunoscându-se legăturile existente între oraşe şi costul deplasării de la un oraş la altul (în cazul în care deplasarea este posibilă). astfel încât suma valorilor celulelor secvenţei să fie maximă. 0 ≤ i0 ≤ m − 1. j ≤ n −1 . a2. astfel încât ai1 < ai2 < . Iniţial acesta se află în oraşul etichetat cu 1. Fie A o tabelă n × n astfel încât A[i][j] ≥0. având prima componentă A[0][0] şi ultima A[n1][n-1]. 6.. trecând o singură dată prin toate celelalte oraşe. Un comis-voiajor trebuie să viziteze n oraşe. 5.j). se cere determinarea tuturor drumurilor posibile pe care le poate efectua comis-voiajorul. 8. iar cele negative reprezintă amenzi.3. 4. 0 ≤ j0 ≤ n − 1 o cameră arbitrară din labirint. S. Să se scrie programul care determină o secvenţă de celule vecine.j). şirul binar NSEV este convertit în baza 10. < aik . Se consideră o matrice A cu m linii şi n coloane reprezentând un labirint. Fie (i0. etichetate cu numere de la 1 la n.. k . Să se scrie programul pentru determinarea numărului minim de culori necesar realizării unei hărţi în care oricare două ţări vecine să fie colorate diferit. Să se scrie un program care determină toate “râuleţele” astfel formate. E. 0 ≤ j ≤ n − 1 semnifică ieşirile din camera (i. Se presupune că în celula A[i0][j0] se “toarnă apă” astfel încât se formează posibil mai multe “râuleţe” (funcţie de diferenţele de nivel). p ≤ n −1 . sau j=p şi i=k ± 1 0 ≤ i . Fie a1.…. Comis-voiajorul doreşte să revină în oraşul din care a plecat. Să se scrie programul pentru determinarea valorii maxime k şi secvenţele 1 ≤ i1<i2<…<ik ≤ n. . 0 ≤ i ≤ m − 1. 0 ≤ i . valoarea fiind memorată în componenta corespunzătoare camerei (i. Valorile pozitive din tabelă reprezintă recompense. j ≤ n −1 . V) se reţine 1. 0 ≤ i .

Sign up to vote on this title
UsefulNot useful