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 rmase 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 din
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.

1
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)

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

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

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

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

3
#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.

4
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 completat 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> // PRODUS CARTEZIAN


#include <fstream.h>
const MAX=20;
int n,v[MAX],w[MAX]; //n-nr. de mulimi, v-vectorul soluie, w-conine nr. de elemente di
//fiecare mulime Sk
void BK(int k);
void citire();
void afisare(int k);
int solutie(int k);
void main()
{citire(); //citire date
BK(1); //apelm funcia BK pentru selectarea primului element n v
}
void BK(int k) //funcia becktreacking
{int i;
for (i=1;i<=w[k];i++) //parcurgem mulimea Sk ={1,2,3,...,wk}
{v[k]=i; //selectm elementul i din mulimea Sk
//nu avem funcie de validare- nu avem condiii de continuare
if (solutie(k)) //verificm dac am obinut o soluie
afisare(k); //afim soluia
else
BK(k+1); //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
}

5
void citire() //citirea datelor
{int i;
ifstream f("prod.in");
f>>n; //se citete numrul de mulimi
for(i=1;i<=n;i++)
f>>w[i]; //se citete numrul de elemente al fiecrei mulimi
f.close();
}
int solutie(int k) //funcia soluie determin momentul n care se ajunge la o soluie
{if (k==n) //obinem o soluie dac am dpus n vectorul v, n elemente
return 1;
return 0;
}
void afisare(int k) //afueaz o soluie
{int i;
for (i=1;i<=k;i++)
cout<<v[i]<<" ";
cout<<endl;
}

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) //verificm dac am obinut o soluie


{if (k==p) //am obinut o aranjare, dac am reuit s depunem n vector p elemente
return 1;
return 0;
}

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)

6
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


s generm pe rnd C n1 , C n2 ,..., C nn 1 , pentru mulimea S={1,2,3, ... ,n}, la care trebuie
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;
}

8
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}

#include <iostream.h> //SUBMULIMI 2


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:

9
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 4 1 3
1 2 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] v[k]
linia i D

linia k D

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 k=1 D
1

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

v k=3
1 4 1 D
v k=3 D
1 4 2 D
-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
D
v k=1
2

v k=2
2 1
v k=2 D
2 2 D
v k=2
2 3
v k=2
2 4

D
v k=3 D
2 4 1 D

v k=4
2 4 1 1
v k=4 D
D
2 4 1 2
D
v k=4 D
2 4 1 3

Algoritmul continu pentru a genera Am obinut prima soluie !


toate soluiile.

11
#include <iostream.h> // DAME
#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);
}
}
}

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 -reine ctigul maxim


sol_max -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 al
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-i-


se 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

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