Sunteți pe pagina 1din 18

8. Metoda de programare Backtracking 8.1. Prezentare general Imaginai-v c astzi este ziua vostr i avei invitai.

Aranjai o mas frumoas, apoi v gndii cum s v aezai invitaii la mas. Ai vrea s tii toate posibilitile de aezare a invitailor la mas, dar realizai n acelai timp c trebuie s inei seama i de preferinele lor. Printre invitai exist anumite simpatii dar i unele antipatii, de care dorii neaprat s inei seama, pentru ca petrecerea s fie o bucurie pentru toi. S ne gndim cum procedai pentru a identifica toate posibilitile de a plasa invitaii la mas. ncepei prin a scrie nite cartonae cu numele invitailor. Alegei un invitat. Pentru a-l alege pe al doilea, selectai din mulimea cartonaelor rma se un alt invitat. Dac tii c cele dou persoane nu se agreeaz, renuntai la cartonaul lui i alegei altul i aa mai departe. Se poate ntmpla ca la un moment dat, cnd vrei s alegei cartonaul unui invitat s constatai c nici unul dintre invitaii rmai nu se potrivete cu ultima persoan slectat pn acum. Cum procedai? Schimbai ultimul invitat plasat cu un invitat dintre cei rmai i ncercai din nou, dac nici aa nu reuiti, schimbai penultimul invitat cu alcineva i ncercai d in nou i aa mai departe pn cnd reuii s plasati toi invitaii. nseamn c ai obinut o soluie. Pentru a obine toate celelalte soluii, nu v rmne dect s o luai de la nceput. Avei cam mult de muncit, iar dac numrul invitailor este mare...operaiunea devine foarte anevoioas. Iat de ce avei nevoie de un calculator i cunotine de programare .

Backtracking este o metod de parcurgere sistematic a spaiului soluiilor posibile al unei probleme. Este o metod general de programare, i poate fi adapt pentru orice problem pentru care dorim s obinem toate soluiile posibile, sau s selectm o soluie optim, din mulimea soluiilor posibile. Backtracking este ns i cea mai costisitoare metod din punct de vedere al timpului de execuie. n general vom modela soluia problemei ca un vector v=(v1,v2,v3,...,vn) n care fiecare element vk aparine unei mulimi finite i ordonate Sk, cu k=1,n. n anumite cazuri particulare, mulimile S1 ,S2, S3,...,Sn pot fi identice . Procedm astfel: 1. La fiecare pas k pornim de la o soluie parial v=( v1,v2,v3,...,vk-1) determinat pn n acel moment i ncercm s extindem aceast soluie adugnd un nou element la sfritul vectorului. 2. Cutm n mulimea Sk , un nou element. 3. Dac exist un element neselectat nc, verificm dac acest element ndeplinete condiiile impuse de problem, numite condiii de continuare. 4. Dac sunt respectate condiiile de continuare, adugm elementul soluiei pariale. 5. Verificm dac am obinut o soluie complet.

dac am obinut o soluie complet o afim i se reia algoritmul de la pasul 1. - dac nu am obinut o soluie, k <----- k+1 si se reia algoritmul de la pasul 1. 6. Dac nu sunt respectate condiiile de continuare se reia algoritmul de la pasul 2. 7. Dac nu mai exist nici un element neverificat n mulimea Sk nseamn c nu mai avem nici o posibilitate din acest moment, s construim soluia final aa c trebuie s modificm alegerile fcute n prealabil, astfel k < ----- k-1 i se reia problema de la pasul 1. Revenirea n caz de insucces sau pentru generarea tuturor soluiilor problemei, a condus la denumirea de backtracking a metodei, traducerea aproximativ ar fi revenire n urm. Forma general a unei funcii backtracking Implementarea recursiv a algoritmului furnizat de metoda backtracking, este mai natural i deci mai uoar. Segmentul de stiv pus la dispoziie prin apelul funciei este gestionat n mod automat de sistem. Revenirea la pasul precedent se realizeaz n mod natural prin nchiderea nivelului de stiv.
void BK(int k) //k-poziia din vector care se completeaz {int i; for (i=1; i<=nr_elemente_Sk; i++) //parcurge elementele mulimii Sk { v[k]=i; //selecteaz un element din mulime if (validare(k)==1) //valideaz condiiile de continuare ale problemei { if (solutie(k)==1) //verific dac s-a obinut o soluie afisare(k); //afieaz soluia else BK(k+1); //reapeleaz functia pentru poziia k+1 } } //dac nu mai exist nici un element neselectat n mulimea Sk, } //se nchide nivelul de stiv i astfel se revine pe poziia k-1 a //vectorului //execuia funciei se ncheie, dup ce s-au nchis toate nivelurile stivei, nseamn c n vectorul v nu mai poate fi selectat nici un elemente din multimile Sk

8.2. Exemple de implementare a metodei: 1. PERMUTRI S se genereze toate permutrile primelor n numere naturale. Vom genera pe rnd soluiile problemei n vectorul v=(v1,v2,v3,...,vn), unde vkSk. S facem urmtoarele observaii: 1. Pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n}. La pasul k selectm un element din mulimea Sk. 2. ntruct n cadrul unei permutri elementele nu au voie s se repete aceast condiie reprezent condiia de continuare a problemei. 3. Obinem o soluie n momentul n care completm vectorul cu n elemente. Exemplu pentru n=3 S1= S2= S3={1,2,3} (1,2,3) (1,3,2) (2,1,3) (2,3,1) (3,1,2) (3,2,1)

v k=1 1 k 1 2 v k=2 1 1 k 1 2 element incorect (se repet) v k=2 1 2 k 1 2 v k=3 1 2 1 k 1 2 element incorect (se repet) v k=3 1 2 2 k 1 2 element incorect (se repet)

STIVA i=1

3
STIVA

i=1 i=1
STIVA i=1,2 i=1 STIVA i=1

i=1,2 i=1 STIVA i=1,2

i=1,2 i=1 STIVA i=1,2,3 i=1,2 i=1

v k=3 1 2 3 k 1 2 3 k=3 s-a obinut o soluie se nchide ultimul nivel de stiv pentru c nu mai sunt elemente n ultima mulime v k=2 1 3 k 1 2 3 v k=3 1 3 1 k 1 2 element incorect (se repet) v 1 3 2 k 1 2 k=3 s-a obinut o soluie

STIVA i=1,2,3 i=1 STIVA i=1

i=1,2,3 i=1 STIVA i=1,2 i=1,2,3 i=1 STIVA i=1,2,3 i=1,2,3 i=1 STIVA i=1,2,3 i=1 STIVA i=1,2

v k=3 1 3 3 k 1 2 3 element incorect (se repet) v k=2 1 3 k 1 2 3 v k=1 2 k 1 2 3 se repet aceiai pai construindu-se soluiile urmtoare

#include <iostream.h> // PERMUTRI const MAX=20; int n,v[MAX] ; //n-nr. de elemente, v[20]-vectorul n care construim soluia int valid(int k); int solutie(int k); void afisare(int k); void BK(int k); int main() {cout<<"n= ";cin>>n; //se citete n BK(1); return 0; //apelm funcia BK pentru completarea poziiei 1din vectorul v } void BK(int k) {int i; //i-elementul selectat din multimea Sk, trebuie sa fie variabil local, pentru // a se memora pe stiv for (i=1;i<=n;i++) //parcurgem elementele mulimii Sk {v[k]=i; //selectm un element din mulimea Sk if (valid(k)) //verificm dac eelementul ales ndeplinete condiiile de continuare {if (solutie(k)) //verificm dac am obinut o soluie afisare(k); //se afieaz soluia obinut else BK(k+1); //reapemm funcia pentru poziia k+1 din vectorul v } } } int valid(int k) //verificm condiiile de continuare {int i; for (i=1;i<=k-1;i++) //comparm fiecare element din vectorul v cu ultimul element selectat if (v[i]==v[k]) //deoarece ntr-o permutare elementele nu au voie s se repete, return 0; //returnm 0 n cazul n care elementul selectat, a mai fost selectat o dat return 1; //returnm 1 n cazul n care elementul nu mai apare n vector } int solutie(int k) //verificm dac am obinut o soluie {if (k==n) //am obinut o permutare, dac am reuit s depunem n vector n elemente return 1; return 0; } void afisare(int k) //afieaz coninutul vectorului v {int i; for (i=1;i<=k;i++) cout<<v[i]<<" "; cout<<endl; }

Problema generrii permutrilor, este cea mai reprezentativ pentru metoda backtracking, ea conine toate elementele specifice metodei. Probleme similare, care solicit determinarea tuturor soluiilor posibile, necesit doar adaptarea acestui algoritm modificnd fie modalitatea de selecie a elementelor din mulimea Sk, fie condiiile de continuare fie momentul obinerii unei soluii.

2. PRODUS CARTEZIAN Se dau n mulimi, ca cele de mai jos: S1={1,2,3,...,w1} S2={1,2,3,...,w2} ......................... Sn={1,2,3,...,wn} Se cere s se gnereze produsul lor cartezian. Exemplu: pemtru n=3 i urmroarele mulimi S1={1,2} w1=2 S2={1,2,3} w2=3 S3={1,2} w3=2 produsul cartezian este: S1 xS2 xS3 ={ (1,1,1),(1,1,2),(1,2,1),(1,2,2),(1,3,1),(1,3,2), (2,2,1),(2,1,2),(2,2,1),(2,2,2),(2,3,1),(2,3,2)} Prin urmare o soluie este un ir de n elemente, fiecare element iSi, cu i=1,n S analizm exemplul de mai sus: 1. La pasul k selectm un element din mulimea Sk ={1,2,3,...,wk}. 2. Elementele unei soluii a produsului cartezian, pot s se repete, pot fi n orice ordine, iar valori strine nu pot apare, deoarece le selectm doar dintre elementele mulimii Sk . Prin urmare nu trebuie s impunem condiii de continuare. 3. Obinem o soluie n momentul n care am com pletat n elemente n vectorul v. Vom memora numrul de elemente al fiecerei mulimi Sk , ntr-un vector w. Soluiile le vom construi pe rnd n vectorul v.
#include <iostream.h> #include <fstream.h> const MAX=20; int n,v[MAX],w[MAX]; void BK(int k); void citire(); void afisare(int k); int solutie(int k); void main() {citire(); BK(1); } void BK(int k) {int i; for (i=1;i<=w[k];i++) {v[k]=i; if (solutie(k)) afisare(k); else BK(k+1); } }
5

//

PRODUS CARTEZIAN

//n-nr. de mulimi, v-vectorul soluie, w-conine nr. de elemente di //fiecare mulime Sk

//citire date //apelm funcia BK pentru selectarea primului element n v //funcia becktreacking //parcurgem mulimea Sk ={1,2,3,...,wk} //selectm elementul i din mulimea Sk //nu avem funcie de validare- nu avem condiii de continuare //verificm dac am obinut o soluie //afim soluia //reapelm funcia BK pentru completarea poziiei urmtoare n // vectorul v //se nchide un nivel de stiv si astfel se ajunge la poziia k-1 n v

void citire() {int i; ifstream f("prod.in"); f>>n; for(i=1;i<=n;i++) f>>w[i]; f.close(); } int solutie(int k) {if (k==n) return 1; return 0; } void afisare(int k) {int i; for (i=1;i<=k;i++) cout<<v[i]<<" "; cout<<endl; }

//citirea datelor //se citete numrul de mulimi //se citete numrul de elemente al fiecrei mulimi //funcia soluie determin momentul n care se ajunge la o soluie //obinem o soluie dac am dpus n vectorul v, n elemente

//afueaz o soluie

3. ARANJAMENTE Se citesc n i p numere naturale cu p<=n. Sa se genereze toate aranjamentle de n elemente luate cte p. Exemplu pentru n=3, p=2 (1,2), (1,3), (2,1), (2,3), (3,1), (3,2) Vom genera pe rnd soluiile problemei n vectorul v=(v1,v2,v3,...,vn), unde vkSk. S facem urmtoarele observaii: 1. pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n}. 2. la pasul k selectm un element din mulimea Sk. ntruct n cadrul unei aranjri, elementele nu au voie s se repete aceast condiie reprezent condiia de continuare a problemei. 3. Oinem o soluie n momentul n care completm vectorul cu p elemente. S observm c problema generrii aranjamentelor, nu difer prea mult de problema generrii permutrilor. Singura deosebire pe care o sesizm este aceea c obinem o soluie n momentul n care am plasat n vector p elemente. Prin urmare, n cadrul programului pentru generarea permutrilor trebuie sa modificm o singur funcie i anume funcia soluie, astfel:
int solutie(int k) {if (k==p) return 1; return 0; } //verificm dac am obinut o soluie //am obinut o aranjare, dac am reuit s depunem n vector p elemente

4. COMBINRI Se citesc n i p numere naturale cu p<=n. S se genereze toate combinrile de n elemente luate cte p. Exemplu pentru n=3, p=2. obinem (1,2), (1,3), (2,3)

Vom genera pe rnd soluiile problemei n vectorul v=(v1,v2,v3,...,vn), unde vkSk. S facem urmtoarele observaii: 1. Pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n}. La pasul k selectm un element din mulimea Sk. 2. n cadrul unei combinri elementele nu au voie s se repete. S mai observm i faptul c dac la un moment dat am generat de exemplu soluia (1,2), combinarea (2,1) nu mai poate fi luat n considerare, ea nu mai reprezint o soluie. Din acest motiv vom considera c elementele vectorului reprezint o soluie, numai dac se afl n ordine strict cresctoare. Acestea reprezint condiiile de continuare ale problemei. 3. Oinem o soluie n momentul n care vectorul conine p elemente. Putem genera toate elementele unei combinri, parcurgnd mulimea {1,2,3,...,n}, apoi s verificm condiiile de continuare aa cum am procedat n cazul permutrilor. Putem ns mbuntii timpul de execuie, selectnd din mulimea {1,2,3,...,n}, la pasul k un element care este n mod obligatoriu mai mare dect elementul v[k -1], adic i=v[k-1]+1. Ce se ntmpl ns cu primul element plasat n vectorul v? Acest element a fost plasat pe poziia 1, iar vectorul v deine i elementul v[0] n mod implicit n C++. v[0]=0, deoarece vectorul v este o variabil global i se iniializeaz automat elementele lui cu 0. n acest fel, impunnd aceste restricii nc din momentul seleciei unui element, condiiile de continuare vor fi respectate i nu mai avem nevoie de funcia valid. Algoritmul a fost substanial mbuntit, deoarece nu selectm toate elementele mulimii i nu verificm toate condiiile de continuare, pentru fiecare element al mulimii.
#include <iostream.h> // COMBINRI const MAX=20; int n,p,v[MAX] ; int solutie(int k); void afisare(int k); void BK(int k); void main() {cout<<"n= ";cin>>n; cout<<"p= ";cin>>p; BK(1); } void BK(int k) {int i; for (i=v[k-1]+1;i<=n;i++) //la pasul k selectm din mulime un element mai mare dect elementul {v[k]=i; //de pe poziia k-1 if (solutie(k)) //nu este necesar s verificam condiiile de continuare, ele sunt respectate afisare(k); //datorit modului n care am selectat elementele. else BK(k+1); } } int solutie(int k) {if (k==p) return 1; return 0;} void afisare(int k) {int i; for (i=1;i<=k;i++) cout<<v[i]<<" "; cout<<endl; }
7

4. SUBMULIMI S se genereze toate submulimile mulimii S={1,2,3, ... ,n}. Exemplu: pentru n=3, S={1,2,3}, submulimile sunt urmtoarele: -mulimea vid, {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3} S observm c pentru a obine toate submulimile unei mulimi, este suficient 1 2 n 1 s generm pe rnd C n , pentru mulimea S={1,2,3, ... ,n}, la care trebuie , Cn ,..., C n s adugm mulimea vid i mulimea S. n aceste condiii, este suficient s modificm doar funcia principal pentru a genera toate submulimile i afiarea datelor ca mulimi de elemente. Funiile BK i soluie genereaz n realitate C np elemente.
#include <iostream.h> // SUBMULIMI 1 const MAX=20; int n,p,v[MAX] ; int solutie(int k); void afisare(int k); void BK(int k); void main() {int i; cout<<"n= ";cin>>n; cout<<"mulimea vida"<<endl; for(p=1;p<=n-1;p++) //generm C np elemente BK(1); cout<<"{"; for(i=1;i<n;i++) cout<<i<<", "; cout<<n<<"}"; } void BK(int k) {int i; for (i=v[k-1]+1;i<=n;i++) {v[k]=i; if (solutie(k)) afisare(k); else BK(k+1); } } int solutie(int k) {if (k==p) return 1; return 0; } void afisare(int k) { cout<<"{ "; for (int i=1;i<k;i++) cout<<v[i]<<", "; cout<<v[k]<<" }"<<endl; }

Putem construi un algoritm mai eficient pentru generarea tuturor submulimilor unei mulimi. De exemplu dac genetm mulimile n urmtoarea ordine: mulimea vid, {1}, {1,2}, {1,2,3}, {2}, {2,3}, {3}
//SUBMULIMI 2

#include <iostream.h> const MAX=20; int n,p,v[MAX] ; int valid(int k); int solutie(int k); void afisare(int k); void BK(int k); void main() {int i; cout<<"n= ";cin>>n; cout<<"mulimea vida"<<endl; BK(1); } void BK(int k) {int i; for (i=v[k-1]+1;i<=n;i++) {v[k]=i; afisare(k); BK(k+1); } }

5. Problema celor n dame Fiind dat o tabl de ah de dimensiune nxn, se cere s se aranjeze cele n dame n toate modurile posibile pe tabla de ah, astfel nct s nu se afle pe aceeai linie, coloan, sau diagonal (damele s nu se atace). Exemplu pentru n=4 o soluie este:

D D D D

Observm c o dam va fi plasat ntotdeauna singur pe o linie. Acest lucru ne permite s memorm fiecare soluie ntr-un vector v, considernd c o csut k a vectorului reprezint linia k iar coninutul ei, adic v[k] va conine numrul coloanei n care vom plasa regina. Pentru exemplul de mai sus, vectorul v va avea urmtorul coninut:

2 1

4 2

1 3

3 4

S facem urmtoarele observaii: 1. Pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n} i reprezint numrul coloanelor tablei de ah. Indicele k reprezint numrul liniei tablei de ah. Prin urmare, la pasul k selectm un element din mulimea Sk.
2.

Condiiile de continuare ale problemei : a) Damele s nu fie pe aceeai linie - aceast condiie este ndeplinit prin modul n care am organizat memorarea datelor i anume ntr -o csu a vectorului putem trece un singur numr de coloan. b) Damele s nu fie pe aceeai coloan adic v[k]v[i], cu 1<=i<=k-1. c) Damele s nu fie pe aceeai diagonal. Dac dou dame se gasesc pe aceeai diagonal nseamn c cele dou distane msutae pe linie respectiv pe coloan, dintre cele dou dame sunt egale. Prin urmare condiia ca damele s nu fie pe aceeai diagonal este: |v[k]-v[i]| k-i , cu 1<=i<=k-1.

v[i] linia i

v[k] D

linia k

3. Obinem o soluie dac am reuit s plasm toate cele n dame, adic k=n. S urmrim modul n care se completeaz vectorul soluie v i o reprezentare grafic a ceea ce nseamn valorile vectorului v pe tabla de ah. Reprezentarea descrie completarea vectorului pn la obinerea primei soluii, pentru n=4. Algoritmul de backtracking continu n aceeai manier, pn la generarea tuturor soluiilor.

10

v 1

k=1

v 1 v 1

k=2 1 k=2 2
D D

k=2 1 3 pe linia 3 nu mai putem plasa nici o dam, selectm alt valoare pe linia 2 v k=2 1 4

D D

v k=3 1 4 1 v k=3 1 4 2 -pe linia 4 nu putem plasa nici o dam -pe linia 3 nici o alt coloan nu este corect -pe linia 2 nu mai exist nici o poziie disponibil -se revine la linia 1 v 2 k=1

D D D

v 2 v 2 v 2 v 2

k=2 1 k=2 2 k=2 3 k=2 4


D D D

v 2

k=3 4 1
D

v 2 v 2 v 2

k=4 4 k=4 4 k=4 4 1 3 1 2


D D Am obinut prima soluie !

D D

Algoritmul continu pentru a genera toate soluiile.

11

#include <iostream.h> #include <math.h> #define MAX 20 int n,v[MAX],sol; int valid(int k); int solutie(int k); void afisare(); void BK(int k); void main() {cout<<"n= ";cin>>n; BK(1); } void BK(int k) {int i; for (i=1;i<=n;i++) {v[k]=i; if (valid(k)==1) {if (solutie(k)==1) sfisare(); else BK(k+1); } } }

//

DAME

int valid(int k) {int i; for (i=1;i<=k-1;i++) if ((v[i]==v[k])||(abs(v[k]-v[i])==(k-i))) return 0; return 1;} int solutie(int k) {if (k==n) return 1; return 0;} void afisare() //afisam solutiile sub forma unei matrice {int i,j,x; sol++; cout<<"\n Solutia: "<<sol<<'\n'; for (i=1;i<=n;i++) {for (j=1;j<=n;j++) if (v[i]==j) cout<<"D "; else cout<<"_ "; cout<<'\n'; } }

12

6. Plata unei sume cu monede de valori date. Fiind dat o sum S i n monede de valori date, s se determine toate modalittile de plat a sumei S cu aceste monede. Considerm c sunt monede suficiente din fiecare tip.
#include <iostream.h> // PLATA SUMEI #include <fstream.h> #define MAX 20 int n=0,x,v[MAX],w[MAX],z[MAX],S,Suma,sol; //v-vectorul soluie,w-valoarea monedelor,z-nr.maxim de monede de un anumit tip void citire(); int valid(int k); int solutie(); void afisare(int k); void BK(int k); void main() {citire(); BK(1); } void BK(int k) {int i; for (i=0;i<=z[k];i++) {v[k]=i; if (valid(k)==1) {if (solutie()==1) afisare(k); else BK(k+1); } } } void citire() {int i; ifstream f("c:\\casa\\sanda\\probleme\\cpp\\back\\monede.in"); f>>S>>n; //se citete suma S i numrul de monede for(i=1;i<=n;i++) {f>>w[i]; //se citesc valorile monedelor z[i]=S/w[i];} //z-memorez numrul maxim de monede de un anumit tip, penru a plati suma S int valid(int k) {int i; Suma=0; for (i=1;i<=k;i++) Suma=Suma+v[i]*w[i]; if ((Suma<=S)&&(k<=n)) return 1; return 0;} int solutie() {if (Suma==S) return 1; return 0;} void afisare(int k) {int i; sol++;cout<<"Solutia :"<<sol<<endl; for (i=1;i<=k;i++) if (v[i]) cout<<v[i]<<" monede de valoarea "<<w[i]<<endl; cout<<endl;}
13

7. Problema rucsacului ntr-un rucsac se poate transporta o anumit greutate maxim G. O persoan dispune de n obiecte. Pentru fiecare obiect se cunoare greutatea i ctigul pe care persoana l poate obine transportnd acelst obiect. Ce obiecte trebuie s transporte persoana respectiv pentru a obine un ctig maxim. Datele de intrare se citesc din fiierul RUCSAC.IN astfel: - linia 1: n G -unde n este numrul de obiecte i G greutatea maxim admis de rucsac - linia i: nume[i] g[i] c[i] unde: -nume este numele obiectului -g este greutatea obiectului - c este catigul obinut pentru acel obiect cu i=1,n Exemplu: RUCSAC.IN 4 20 pantaloni 5 5 caciula 10 3 camasa 10 7 pantofi 5 2 pentru datele de intrare de mai sus, soluia optim este: Castigul maxim:14 pantaloni 5 5 camasa 10 7 pantofi 5 2 Dup cum observai prolema nu solicit obinerea tuturor soluiilor ci determinarea soluiei optime. Pentru a determina soluia optim vom genera cu metoda backtracking toate soluiile i vom reine dintre acestea doar soluia cea mai bun. Aceasta presupune s nu afim fiecare soluie ci, n momentul obinerii unei noi soluii o vom compara cu soluia precedent, n cazul n care ctigul obinut este mai mare dect precedentul vom reine aceast soluie. Vom considera ctigul iniial 0. Vom folosi urmtoarele variabile: n-numrul de obiecte G - greutatea maxim admis de rucsac nume[ ][ ] - reinem renumirea obiectelor g[ ] - reinem greutatea fiecrui obiect c[ ] -reinem ctigul pentru fiecare obiect v[ ] -vectorul soluie: 0-obiectul nu este transportat, 1-obiectul este transportat s_max sol_max -reine ctigul maxim -reine soluia maxim

14

#include <stdio.h> #include <iostream.h> #include <fstream.h> #define MAX 20 int n,v[MAX],sol_max[MAX],g[MAX],c[MAX],s,s_max,G,gr,nr_sol; char nume[MAX][MAX]; void back(int k); int valid(int k); void optim(); void citire(); void afisare(); main() {citire(); back(1); afisare(); //afisam solutia optima } void back(int k) { int i; for(i=0;i<=1;i++) {v[k]=i; //0-obiectul k sete NEselectat, 1-obiectul k este selectat if (valid(k)) if (k==n) optim(); //din multimea solutiilor vom retine doar solutia optima else back(k+1); } } int valid(int k) { gr=0; for(int j=1;j<=k;j++) gr=gr+v[j]*g[j]; //-insumam greutatile obiectelor selectate pana la pasul k if(gr<=G) return 1 //verificam daca greutatea cumulata nu depaseste greutatea maxima G else return 0; } void optim() {int s=0; nr_sol++; for(int j=1;j<=n;j++) s=s+v[j]*c[j]; //s-calculam suma ctigurilor obiectelor selectate if((nr_sol==0)||(s>s_max)) //daca s>suma maxima, solutia este mai buna {s_max=s; //retinem solutia in sol_max for(j=1;j<=n;j++) sol_max[j]=v[j]; } } void citire() { ifstream f("RUCSAC.IN"); f>>n>>G; //n-nr. obiecte, G-greutatea maxima for (int i=1;i<=n;i++) f>>nume[i]>>g[i]>>c[i]; //se citeste greutatea si ponderea fiecarui obiect f.close(); } void afisare() { nr_sol++; cout<<"Castigul maxim:"<<s_max<<"\n"; for (int j=1;j<=n;j++) if(sol_max[j]) cout<<nume[j]<<" "<<g[j]<<" "<<c[j]<<endl; cout<<"\n"; }
15

8.3. Evaluare TESTUL 1 1. Cnd este necesar ca n rezolvarea unei probleme s aplicm metoda backtracking? 2. Ne propunem s generm toate submulimile mulimii {1, 2, 4, 6, 8}. Cte soluii care obligatoriu conin elementul 2 i nu onin elementul 8 putem genera? a.) 8 b.) 6 c.) 16 d.) 7 3. S se scrie un numr natural n ca sum de numere neturale nenule distincte. 4. Dac scriem numrul 9 ca sum de numere naturale distincte, aplicnd metoda backtracking i obinem toate soluiile n ordinea: 1+2+6, 1+3+5, 1+8, 2+3+4, 2+7, 3+6 i 4+5, aplicnd aceeai metod pentru scrierea lui 12 ca sum, aplicnd exact aceeai metod de generare, Cte soluii de forma 3+... exist? a.) 7 b.) 2 c.) 1 d.) 4 TESTUL 2 1. Descriei etapele obligatorii de analiz, a unei probleme pe care trebuie s o rezolm cu metoda backtracking. 2. Presupunnd c avem mulimea {2, 4, 6} i generm cu backtracking toate numerele care se pot forma cu aceste cifre n ordine strict cresctoare, nu neaprat n aceast ordine: 2, 4, 24, 6, 26, 46, 246. Problema este echivalent cu a genera: a.) permutri de k obiecte b.) aranjamente de 10 obiecte luate cte k c.) submulimilor nevide ale unei mulimi d.) partiiilor unei mulimi 3. S se genereze toate numerele care se pot forma cu cifre aflate n ordine strict descresctoare, din mulimea {2, 4, 6, 8} . 4. Avei n invitai la mas. Printre persoanele invitate exist cteva care nu se agreeaz i nu dorii s ajung alturi. Determinai toate modalitile de a plasa la mas nvitaii innd seama de aceste restricii. Datele de intrare se ciresc din fiierul back.in astfel: linia 1: n -numrul de persoane linia 2: p1 p2 -dou persoane care nu trebuie sa stea alturi linia 3: p3 p4 - .................... linia k: pl pm - -

16

8.4. Probleme propuse 1. S se afieze toate modalitile n care poate fi ordonat mulimea {1,2,...,n} astfel ca numerele 1,2,3 s fie alturate i n ordine crescatoare(n>3). 2. Fie dat o mulime A cu m elemente i o mulime B cu n elemente. S se gseasc numarul de permutri al mulimii AUB, astfel nct primul element a l unei astfel de permutri sa fie din A, iar ultimul s fie din B, tiind c A i B sunt disjuncte. S se afieze toate aceste permutri. 3. O grup de studeni trebuie s programeze 4 examene n timp de 8 zile. Afiai toate modalitile n care se poate face aceasta. Dar dac ultimul examen se va da in mod obligatoriu n ziua a opta? 4. La n clase trebuie repartizai m profesori de matematic fiecaruia repartizndu -ise cte m clase (m<=n). Determinai toate modalitile n care se poate face repartizarea. 5. Din 10 persoane, dintre care 6 brbai i 4 femei se formeaz o delegaie alctuit din 5 persoane dintre care cel puin doua femei. Afiai toate modalitile n care se poate forma aceasta delegaie. 6. n cte moduri se poate ordona mulimea {1,2,..,n} astfel nct fiecare numr divizibil cu 2, i fiecare numr divizibil cu 3, s aib rangul divizibil cu 2 i respectiv 3? Afiai toate soluiile. 7. Pentru ntocmirea orarului unei clase de elevi, trebuie s fie programat n fiecare zi, fie o or de desen din cele dou pe sptmn, fie o ora de fizic din cele patru pe sptmn. Afiai toate modalitile de ntocmire a orarului. 8. La o petrecere iau parte 7 fete si 8 baiei. La un anumit dans trebuie s se formeze 4 perechi. n cte moduri se pot forma aceste perechi? Afiai toate soluiile. 9. Un elev are n cri de matematic i altul are m cri. n cte moduri pot s schimbe crile ntre ei, o carte n schimbul alteia? Dar dac schimb dou cri n schimbul altora 2? Afiai toate soluiile. 10. Fiind dat o hart cu n ri, se cer toate soluiile de colorare a hrii, utiliznd cel mult 4 culori, astfel nct dou ri cu frontier comun s fie colorate diferit. 11. Se dau n cuburi numerotate de la 1 la n, de laturi l i si culori ci cu care se pot forma turnuri, respectnd condiiile: - cuburile din turn au laturile n ordine descrescatoare; - cuburi alaturate au culori diferite. Folosind k din cele n cuburi, se cere sa se afieze: a. toate turnurile ce se pot forma; b. un turn; c. un turn de naltime maxim;

17

d. toate turnurile de naltime maxim (far a genera de 2 ori toate turnurile posibile).

18