Sunteți pe pagina 1din 87

Metoda Backtracking

1. Aspecte teoretice
2. Exemplu pentru nelegerea metodei
3. Permutri
4. Aranjamente
5. Combinri
6. Problema celor n dame
7. Problema colorrii hrilor
8. Problema comis voiajorului
9. Problema plaii unei sume s utiliznd m tipuri de monede
10. Backtracking recursiv
11. Aranjamente si permutari rezolvate recursiv
1. Aspecte teoretice
Metoda Backtracking este o metod de elaborare a algoritmilor.
Ea se aplic problemelor n care soluia se poate reprezenta sub
forma unui vector, X=(x1,x2,...xm), care aparine lui
S=S1xS2x...Sm

- S=S1xS2x...Sm se numete spaiul soluiilor posibile
- Pentru fiecare problem n parte se dau anumite condiii ntre
componentele vectorului soluie care se numesc condiii
interne
- Soluiile posibile care verific condiiile interne se
numesc soluii rezultat
- Metoda Backtracking i propune s genereze toate soluiile
rezultat
O metod simpl de a genera soluiile
rezultat const n a genera ntr-un mod
oarecare toate soluiile posibile i de a
alege dintre acestea doar pe cele care
verific condiiile interne. Dezavantajul
const n faptul c timpul cerut este
foarte mare.
Metoda Backtracking urmrete s evite generarea
tuturor soluiilor posibile. Pentru aceasta elementele
vectorului x primesc pe rnd valori n sensul c lui xk i se
atribuie o valoare doar dac componentele din faa sa x1,
x2,...xk-1 au primit valori.
Dac lui xk i s-a atribuit o valoare, nu se trece direct la
atribuirea de valori lui xk+1, ci se verific nite condiii
de continuare, referitoare la x1, x2,...xk-1 xk. Dac
condiiile de continuare au fost satisfcute, se trece la
calculul lui xk+1. Nendeplinirea lor exprim faptul c
oricum s-ar alege xk+1,...,xn, nu se va ajunge la o soluie
rezultat. Evident, ca n cazul nendeplinirii condiiilor de
continuare va trebui s se fac o alt alegere pentru xk.
Sau dac Sk a fost epuizat, s se micoreze k cu o unitate,
ncercnd s se fac o nou alegere pentru xk.
2. Exemplu pentru nelegerea
metodei
Pentru a nelege mai uor prezentm urmtorul exemplu:
Presupunem c dorim s ne mbrcm de la un magazin
pentru o festivitate i dorim s cumprm: pantofi, ciorapi,
pantaloni, cma i cravata astfel nct acestea s se
asorteze ntre ele, s se genereze toate modalitile de a ne
mbrca.

Magazinul are:
5 etaje
La etajul 1 are 10 raioane cu pantofi
La etajul 2 are 10 raioane cu ciorapi
La etajul 3 are 10 raioane cu pantaloni
La etajul 4 are 10 raioane cu cmi
La etajul 5 are 10 raioane cu cravate
Deoarece soluia are mai multe componente, 5 cte etaje
are magazinul, putem folosi metoda Backtracking. Pentru
rezolvare vom folosi:
k : variabil ntreag care reprezint etajul pe care ne
gsim
x : vector care are 5 componente ntregi, adic exact cte
etaje are magazinul cu proprietatea c xk reprezint numrul
raionului de la care s-a cumprat pe etajul k. n cazul de fa
xke {1,...,10} unde ke{1,...,5}
as este o variabil ntreag care primete valoarea 1 dac
pe etajul k mai sunt raioane nevizitate i primete valoarea
0 dac pe etajul k nu mai sunt raioane nevizitate.
ev este o variabil ntreag care primete valoarea 1 dac ce
este la raionul xk convine i primete valoarea 0 dac este la
raionul xk nu convine.
se pleac de la primul etaj
din faa uii
atta timp ct nc ne aflm la un etaj , k
repetm
ne ntrebm dac mai sunt raioane pe etajul k
dac da, atunci
se verific dac ne convine ce conine raionul care urmeaz
atta timp ct mai sunt raioane i nu am gsit ce ne place.
dac am gsit atunci
dac le-am luat pe toate
atunci
se afieaz
altfel
se merge la etajul urmtor n faa uii
altfel
se coboar la etajul de jos
Cum se procedeaz:

k=1; (se pleac de la primul etaj)
x[k]=0; (din faa uii)
while (k>0) (atta timp ct nc ne aflm la un etaj , k)
{
do (repetm)
{
succ(x,k,as); (ne ntrebm dac mai sunt raioane pe etajul k)
if(as) (dac da, atunci)
valid(x,k,ev); (se verific dac ne convine ce conine raionul
care urmeaz)
}
while(as&&!ev); (atta timp ct mai sunt raioane i nu am gasit ce ne place.)
if (as) (dac am gsit atunci)
if(k==5) (dac le-am luat pe toate atunci)
afis(x,k) (se afieaz)
else (altfel)
{
k=k+1; (se merge la etajul urmtor)
x[k]=0; (n faa uii)
}
else (altfel)
k=k-1; (se coboar la etajul de jos)
}
Reprezentarea a ceea ce s-a spus mai sus este:

Cum ne dm seama dac mai
sunt raioane la etajul k?
dac numrul raionului de la etajul k este mai
mic dect 10
atunci
mai sunt raioane pe etajul k
i mergem la raionul urmtor
altfel
nu mai sunt raioane pe etajul k
void succ(sir x,int k,int &as) (funcia care determin dac mai
sunt raioane la etajul k)
{
if(x[k]<10) (dac numrul raionului de la etajul k este mai
mic dect 10)
{ (atunci)
as=1; (mai sunt raioane pe etajul k)
x[k]=x[k]+1 (i mergem la raionul urmtor)
}
else (altfel)
as=0; (nu mai sunt raioane pe etajul k)
}
Cum se realizeaz afiarea

pentru i de la 1 la k
se afieaz x[i]
cursorul trece la linia urmtoare
void afis(sir x, int k)
{
int i;
for(i=1;i<=k;i++) (pentru i de la 1 la k)
cout<<x[i]<< ; (se afieaz x[i])
cout<<endl; (cursorul trece la linia urmtoare)
}
void valid(int &ev)
{
ev=1; (presupunem c orice alegere de haine
ne convine)
}
Pentru realizarea programului se parcurg
urmtoarele etape:
construirea tipului sir
declararea tuturor variabilelor care apar n
cadrul programului principal
realizarea funciei succ
realizarea funciei valid
realizarea funciei afi
programul principal care conine rutina
principal
construirea tipului sir
#include<iostream.h>
#include<stdio.h>
typedef int sir[100];
sir x;
declararea tuturor variabilelor care apar n
cadrul programului principal
int k, as,ev;
realizarea funciei succ
void succ(sir x, int k, int&as)
{
if(x[k]<10)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
Verific dac mai sunt sau nu raioane pe etajul k
realizarea funciei valid
void valid(int&ev)
{
ev=1;
}
Am gsit ce mi place
realizarea funciei afi
void afis(sir x,int k)
{
int i;
for(i=1;i<=k;i++)
cout<<x[i]<<" ";
cout<<endl;
}
Afiarea rezultatului
programul principal care conine
rutina principal
int main(void)
{
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if (as)

valid(ev);
}
while(as&&!ev);
if(as)
if(k==5)
afis(x,k);
else
{

k=k+1;

x[k]=0;
}
else k=k-1;
}
}

Comentarii
1.
Dac
la etajul 1 ar fi fost n1
raioane
la etajul 2 ar fi fost n2
raioane
.......
la etajul k ar fi fost nk
raioane

Funcia succesor se
modific astfel:

void succ(sir x, int k,
int&as)
{
if(x[k]<n[k])
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
Comentarii
2.
Dac magazinul are m etaje atunci condiia dac
s-au fcut toate cumprturile sau s-a ajuns la
ultimul etaj se scrie

if(k==m)
Comentarii
3.
Dac la fiecare etaj numrul de magazine
este variabil (nu 10) condiia de testare
din funcia succesor este

if(x[k]<n[k])
Atunci cnd nu exist condiii ntre
componentele vectorului soluie
funcia valid are forma:

void valid(int&ev)
{
ev=1;
}
Atunci cnd componentele vectorului soluie trebuie s fie
distincte trebuie artat c xk=xi pentru i=1...k-1 se procedeaz astfel:

- se presupune c xk este diferit de toate elementele din faa sa
- se parcurg indicii 1...k-1 cu i
- dac xk nu este diferit de xi, atunci presupunerea este fals

void valid(int&ev)
{
int i;
ev=1;
for(i=1;i<=k-1;i++)
if(!(x[k]!=x[i]))
ev=0;
}
X[k] nu este diferit de x[i]
Permutri
O permutare a unei mulimi cu n elemente este un ir de
elemente obinut prin schimbarea ordinii elementelor
mulimii date sau chiar mulimea nsi.
Ne gndim la generarea permutrilor atunci cnd se d o
mulime cu n elemente ca date de intrare iar soluia este sub
forma de vector, tot cu n elemente, ale crui componente sunt
distincte i aparin mulimii date.
Exemplu: Fie A={1,2,3}. Permutrile mulimii A sunt: (1,2,3),
(1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1).

Fie A={a1, a2,,am} o mulime cu elemente de tip ntreg.
Trebuie determinate elementele mulimii { y1, y2,,ym }| ykeA,
k=1,2,...,m, pentru yi=yj pentru i=j}.
Deci, x=( x1, x2,,xm) unde xe{1,...,m}, elementele vectorului
x trebuie s fie distincte.
Programul:
#include<iostream.h>
#include<stdio.h>
typedef int sir[100];
sir x;
int i,k,m;
int as,ev;
sir a;
void succ(sir x, int k, int &as)
{
if(x[k]<m)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int &as)
{
int i;
ev =1;
for(i=1;i<=k-1;i++)
if(!(x[i]!=x[k]))
ev=0;
}
void afis(sir x, int k)
{
int i;
for(i=1;i<=k;i++)
cout<<a[x[i]]<<" ";
cout<<endl;
}
int main(void)
{
cout<<"m=";
cin>>m;
for(i=1;i<=m;i++)
cin>>a[i];
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if(as)
valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==m) afis(x,k);
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
}
Aranjamente
Se dau dou mulimi A={1,2,,p} i
B={1,2,,m} se cer toate funciile injective
definite pe A cu valori n B. O astfel de problem
este una de generare a aranjamentelor de n luate
cate p (A
n
p
).
Exemplu: p=2, n=3. Avem (1,2), (2,1), (1,3),
(3,1), (2,3), (3,2). De exemplu (2,1) este funcia
f:AB dat astfel f(1)=2, f(2)=1. Avem relaiile:
=m(m-1)...(m-p+1).
Avem relaiile:
) (
!
p m
m
A
p
n

=
= m(m-1)...(m-p+1).
Se citesc m i p. S se genereze toate aranjamentele de m
luate cte p.
Se observ c dac se cunoate fiecare submulime de p
elemente a mulimii de m elemente, atunci aranjamentele se pot
obine permutnd n toate modurile posibile elementele unei
astfel de mulimi.
O soluie este de forma: x1,x2,...xp unde x1,x2,...xpeB. n
plus x1,x2,...xp trebuie s fie distincte. O soluie are p numere
din mulimea B i numerele trebuie s fie distincte.
De aici rezult c algoritmul este acelai ca la permutri,
diferena fiind dat de faptul c soluia are p numere, nu m ca n
cazul permutrilor.
#include<iostream.h>
#include<stdio.h>
typedef int sir[100];
sir x;
int i,k,m,p;
int as,ev;
sir a;

void succ(sir x, int k, int &as)
{
if(x[k]<m)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int
&as)
{
int i;
ev =1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i])
ev=0;
}
void afis(sir x, int k)
{
int i;
for(i=1;i<=k;i++)
cout<<a[x[i]]<<" ";
cout<<endl;

}
se verific dac xk=xi
unde i=1,2,...,k-1
se afieaz elementele din mulimea A
care corespund poziiilor date de
elementele vectorului x
int main(void)
{
cout<<"m=";
cin>>m;
for(i=1;i<=m;i++)
cin>>a[i];
cout<<"p=";
cin>>p;
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if(as) valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==p) afis(x,k);
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
}
Combinri
Fiind dat o mulime A cu n elemente, a combina
elementele mulimii n grupe de cte p<n elemente
nseamn a determina toi vectorii cu p elemente ale
cror componente aparin mulimii A i sunt sortate
cresctor.
Ne gndim la generarea combinrilor atunci cnd se
d o mulime cu n elemente ca date de intrare iar soluia
este sub forma unui vector cu p<n elemente, astfel nct
s nu aib importan ordinea pe care o au n cadrul
irului. Componentele sunt sortate cresctor i
aparin mulimii date.
Fie A={1,2,3}. Combinrile mulimii A n grupe de cte
dou elemente sunt (1,2), (1,3), (2,3).
#include<iostream.h
>
#include<stdio.h>
typedef int sir[100];
sir x;
int i,k,m,p;
int as,ev;
sir a;

void succ(sir x, int k, int &as)
{
if(x[k]<m)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int &as)
{
int i;
ev =1;
for(i=1;i<=k-1;i++)
if((k>=2)&&!(a[x[k]]>a[x[k-1]]))
ev=0;
}
void afis(sir x, int k)
{
int i;
for(i=1;i<=k;i++)
cout<<a[x[i]]<<" ";
cout<<endl;

}
se verific dac componentele
aparin mulimii date i sunt
sortate cresctor
se afieaz elementele din mulimea A care
corespund poziiilor date de elementele vectorului x
int main(void)
{
cout<<"m=";
cin>>m;
for(i=1;i<=m;i++)
cin>>a[i];
cout<<"p=";
cin>>p;
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if(as) valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==p) afis(x,k);
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
}
Problema celor n dame
Pentru rezolvare se vor folosi:
k = variabila ntreag ce reprezint linia pe care se
aeaz a k-a dam
x = vector cu componente ntregi cu proprietatea
c xk reprezint coloana pe care se aeaz a k-a
dam

Deoarece tabla are n linii i n coloane ke{1,2,..,n}
si x
k
e{1,2,...,n} adic:
x=(x1,x2,...,xn) unde x
k
e{1,2,n}, ke{1,2,...,n}.
n desenul de mai jos este ilustrat situaia n care
dama k i dama i sunt situate pe aceeai
diagonal.
k
i
x
i
x
k

k-i=x
k
-x
i
(trebuie ca damele s fie aezate
n colurile unui ptrat cu latura
K-i, respectiv x
k
-x
i
)
n desenul de mai jos este ilustrat situaia n care
dama k i dama i sunt situate pe aceeai
diagonal.
k
i
x
k
x
i

k-i=x
i
-x
k
(trebuie ca damele s fie aezate
n colurile unui ptrat cu latura
K-i, respectiv x
i
-x
k
)
Dama k i dama i se gsesc pe aceeai
diagonal dac k-i=|x
k
-x
i
|
Dama k i dama i se gsesc pe aceeai
coloan dac x
k
=x
i
.
Dama k i dama i nu se afl e aceeai
lunie niciodat datorit modului de
construire a vectorului x
Funcia valid trebuie s verifice dac dama k nu
se afl pe aceeai coloan sau pe aceeai
diagonal cu dama i.

Deci trebuie artat c:

x
k
=x
i
i k-i=|x
k
-x
i
| pentru i=1,2,,k-1.
adic
if((x[k]==x[i])||(k-i==abs(x[k]-x[i])))
typedef int sir[100];
sir x;
int i,k,n;
int as,ev;

void succ(sir x, int k, int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int &ev)
{
ev =1;
for(i=1;i<=k-1;i++)
if((x[k]==x[i])||(k-
i==abs(x[k]-x[i])))
ev=0;
}
void afis(sir x,int k)
{
int i;
for(i=1;i<=k;i++)
cout<<x[i]<<" ";
cout<<endl;
}
int main(void)
{
cout<<"n=";
cin>>n;
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if(as)
valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==n) afis(x,k);
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
}

Problema colorrii hrilor
Fiind dat o hart cu n tri, se cer toate modalitile
de colorare a hrii, utiliznd cel mult m culori, astfel
nct dou ri cu frontier comun s fie colorare
diferit. Este demonstrat faptul c sunt suficiente numai 4
culori ca orice hart s poat fi colorat.

Pentru rezolvare se vor folosi:
k: variabil ntreag, care reprezint o ar
x: vector cu componente ntregi cu proprietatea x
k

reprezint culoarea rii cu numrul k
deoarece sunt n ri i m culori, k={1,...,n} i
x
k
={1,...,m}
x=(x
1
,x
2
,...,x
n
) unde x
k
e{1,...,n}.

=
=
=
e sunt vecin nu j tara si i tara daca 0
e sunt vecin j tara si i tara daca 1
,
,
j i
j i
a
a
A
1
2
3
4
5
Pentru reprezentarea hrii n program se va folosi matricea de adiacen definit
astfel:

Exemplu: pentru harta de mai jos:

Matricea de adiacen este:

|
|
|
|
|
|
.
|

\
|
=
0 1 1 1 1
1 0 1 1 1
1 1 0 0 0
1 1 0 0 1
1 1 0 1 0
A
Concluzie:
ara k i ara i sunt vecine, dac (a
i,k
=1) sau
(a
k,i
=1)
ara k i ara i au aceeai culoare dac x
k
=x
i

Comentarii la funcia valid:
Trebuie verificat dac ara k i ara i ce sunt
ri vecine au culori diferite, adic dac
a
k,i
=1 pentru x
k
=x
i
, pentru i=1...k-1.
#include<iostream.h>
#include<math.h>
typedef int sir[100];
sir x;
int m,i,k,n,j;
int as,ev;
int a[100][100];
void succ(sir x, int k, int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int &ev)
{
ev =1;
for(i=1;i<=k-1;i++)
if((a[k][i]==1)&&(x[k]==x[i]))
ev=0;
}


void afis(sir x,int k)
{
int i;
for(i=1;i<=k;i++)
cout<<x[i]<<" ";
cout<<endl;
}
Se verific dac a
i,k
=1 atunci
x
k
=x
i
, unde i=1,...k-1
int main(void)
{
cout<<"Dati numarul de tari:";
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{

cin>>a[i][j];

a[j][i]=a[i][j];
}
k=1;
x[k]=0;
while(k>0)
{
do
{
succ(x,k,as);
if(as) valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==n) afis(x,k);
else
{
k=k+1; x[k]=0;
}
else k=k-1;
}
}
Problema comis voiajorului
Un comis voiajor trebuie s viziteze un numr
de n orae. Iniial acesta se afl ntr-unul din ele,
notat 1. Comis voiajorul dorete s nu treac de
dou ori prin acelai ora iar la ntoarcere s
revin n oraul 1. Cunoscnd legturile existente
ntre orae, se cere s se tipreasc toate
drumurile posibile pe care le poate efectua comis
voiajorul.
Pentru rezolvarea problemei se vor folosi:
k: variabil ntreag care reprezint la al ctelea
ora s-a ajuns (al doilea, al treilea...)
x: vector cu componente ntregi, cu proprietatea
c x
k
reprezint al k-lea ora din traseu
Pentru a evita parcurgerea unui drum de
dou ori, se va recurge la strategia de a
atribui lui x
1
valoarea 1, adic toate
drumurile s plece de la primul ora. Din
acest motiv, x
k
e{2,,n} pentru ke{2,,n}.

x=(x
1
,x
2
,,x
n
) unde xke{2,,n} i x
1
=1,
pentru ke{2,,n}.
Observaie: Pentru reprezentarea grafului seva
folosi matricea e adiacen definit astfel:

a
i,j
=1, dac exist drum ntre oraele i i j
a
i,j
=0, dac nu exist drum ntre oraele i i j
Exemplu: pentru harta de mai
jos,
1
2
3
4
5
matricea de
adiacen este:
|
|
|
|
|
|
.
|

\
|
=
0 0 1 1 1
0 0 1 1 1
1 1 0 0 0
1 1 0 0 1
1 1 0 1 0
A
Concluzii:
ntre oraele k i i exist drum dac a
k,i
=1 i
(a
i,k
=1), deci ntre oraele x
k
i x
i
exist drum
dac a[x
k
][x
i
]=1 (i a[x
i
][x
k
]=1)
oraul x
k
trebuie s fie diferit de oraul x
i
pentru
i=1...k-1
oraul x
n
trebuie s fie vecin cu oraul x
1
adic
a[x
k
][x
1
]=1
Comentarii la funcia Valid:
Trebuie verificat dac:
- exist drum ntre oraele x
k-1
i x
k
adic trebuie
de verificat dac a[x
k-1
][x
k
]=1;
- oraul x
k
este diferit de toate oraele prin care
s-a trecut adic x
k
=x
i
pentru i=1..k-1
- dac s-a ajuns la al n-lea ora, trebuie s existe
un drum ntre acesta i primul ora adic dac
k=n trebuie a[x
k
][x
1
]=1
Programul
#include<iostream.h>
#include<math.h>
typedef int sir[100];
sir x;
int i,j,k,n,as,ev;
int a[100][100];
void succ(sir x, int k, int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(sir x, int k, int &ev)
{
ev =1;
if(a[x[k-1]][x[k]]==0) ev=0;
else
{
for(i=1;i<=k-1;i++)
if(x[i]==x[k]) ev=0;
if((k==n)&&(a[x[n]][x[1]]==0)) ev=0;
}
}
void afis(sir x,int k)
{
int i;
for(i=1;i<=k;i++)
cout<<x[i]<<" ";
cout<<endl;
}
int main(void)
{
cout<<"Dati numarul de orase:";
cin>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
cin>>a[i][j];
a[j][i]=a[i][j];
}
x[1]=1;
k=2;
x[k]=1;
while(k>1)
{
do
{
succ(x,k,as);
if(as) valid(x,k,ev);
}
while(as&&!ev);
if(as)
if(k==n) afis(x,k);
else
{
k=k+1;
x[k]=1;
}
else k=k-1;
}
}
Pentru exemplul dat mai sus, si matricea de
adiacen corespunztoare, drumurile posibile
sunt:

1 2 4 3 5
1 2 5 3 4
1 4 3 5 2
1 5 3 4 2
1
2
3
4
5
Problema plii unei sume s
utiliznd m tipuri de monede
Se dau suma s si m tipuri de monede avnd
valorile a1, a2, ..., am lei. Se cer toate
modalitile de plat a sumei s utiliznd aceste
monede.

Va trebui s se genereze toi vectorii de forma
X=(x1,...xm), care verific relaia:
x
1
a
1
+x
2
a
2
+...+x
m
a
m
=S
Din aceast relaie se poate vedea c:
x
1
poate lua valori ntre 0 i n
1
=
x
2
poate lua valori ntre 0 i n
2
=
......................................................
x
k
poate lua valori ntre 0 i n
k
=
.......................................................
x
m
poate lua valori ntre 0 i n
m
=

Trebuie s se determine elementele mulimii:
{x1,,xm}| xke{0,,m} unde k=1,,m i
x
1
a
1
+x
2
a
2
+...+x
m
a
m
=S
(

1
a
S
(

m
a
S
(

k
a
S
(

2
a
S
Exemplu: S=3; m=2, a[1]=1, a[2]=2.
Programul va genera soluiile:
(1,1) ce corespunde la 1a1+1a2=11+12=3
(3,0) ce corespunde la 3a1+0a2=31+02=3
0 1 n
m

0 1 n
m-1


0 1 n
2


0 1 n
1

1
k
m
x
k
n
k
Programul
#include<iostream.h>
typedef int sir[100];
sir x,n,a;
int m,i,k,S,as,ev;
void succ(sir x, int k, int &as)
{
if(x[k]<n[k])
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void valid(int &ev)
{
ev =1;
}
void afis(sir x,int k)
{
int i,s1;
s1=0;
for(i=1;i<=k;i++)
s1=s1+x[i]*a[i];
if(S==s1)
{
for(i=1;i<=k-1;i++)
cout<<x[i]<<"*"<<a[i]<<"+";
cout<<x[k]<<"*"<<a[k]<<"="<<S<<endl;
}
}
int main(void)
{
cout<<"Dati valoarea sumei:"; cin>>S;
cout<<"Dati numarul monedelor m="; cin>>m;
cout<<"Dati valorile celor "<<m<<" monede: ";
for(i=1;i<=m;i++)
{
cin>>a[i];
n[i]=S/a[i];
}
k=1;
x[k]=-1;
while(k>0)
{
do
{
succ(x,k,as);
if(as) valid(ev);
}
while(as&&!ev);
if(as)
if(k==m) afis(x,k);
else
{
k=k+1;
x[k]=-1;
}
else k=k-1;
}
}
Bactracking recursiv
void back(int k)
{
if(solutie(k)) afis(x,k);
else
{
x[k]=0;
while(succ(x,k))
{
valid(x,k,ev)
if(ev)
back(k+1);
}
}
}
1. Funcia back are un parametru
ntreg k i funcioneaz astfel:
- dac s-a ajuns la o soluie, se
tiprete i se revine la nivelul
anterior
- dac nu s-a ajuns la o soluie
- se iniializeaz nivelul
- atta timp ct este
succesor pe acest nivel
- dac este valid,
funcia back se autoapeleaz pentru
k+1
- dac nu este succesor, se
trece pe nivelul k-1 prin ieirea din
funcia back.

Se apeleaz back(1)
2. Funcia succ verific dac mai sunt elemente n Sk.
3. Funcia valid verific dac sunt satisfcute condiiile de
continuare
4. Funcia afi afieaz o soluie rezultat
5. Funcia soluie returneaz
1 dac pe nivelul k s-a ajuns la soluie
0 dac pe nivelul k nu s-a ajuns la soluie

n general funcia soluie se definete astfel:
int soluie(int k)
{
return(k==n+1)
}
Permutri recursiv
funcia succ
#include<iostream.h>
typedef int sir[100];
sir x;
int i,k,n,ev;

int succ(sir x, int k)
{
if(x[k]<n)
{
x[k]=x[k]+1;
return 1;
}
else return 0;
}
void valid(sir x, int k, int&ev)
{
int i;
ev=1;
for(i=1; i<=k-1;i++)
if(!(x[k]!=x[i])) ev =0;
}

void afis(sir c, int k)
{
int i;
for(i=1;i<=k-1;i++)
cout<<x[i]<<" ";
cout<<endl;
}
funciile valid i afi
void back(int k)
{
if (k==n+1) afis(x,k);
else
{
x[k]=0;
while(succ(x,k))
{
valid(x,k,ev);
if(ev)
back(k+1);
}
}
}
funcia back
programul principal
int main(void)
{
cout<<"n=";
cin>>n;
back(1);
}
Aranjamente - recursiv
#include<iostream.h>
typedef int sir[100];
sir x;
int i,k,n,ev,m;

int succ(sir x, int k)
{
if(x[k]<n)
{
x[k]=x[k]+1;
return 1;
}
else return 0;
}
Funciile valid i afi
void valid(sir x, int k, int&ev)
{
int i;
ev=1;
for(i=1; i<=k-1;i++)
if((x[k]==x[i])) ev =0;
}

void afis(sir c, int k)
{
int i;
for(i=1;i<=k-1;i++)
cout<<x[i]<<" ";
cout<<endl;
}
Funcia back
void back(int k)
{
if (k==m+1) afis(x,k);
else
{
x[k]=0;
while(succ(x,k))
{
valid(x,k,ev);
if(ev)
back(k+1);
}
}
}
programul principal
int main(void)
{
cout<<"n=";
cin>>n;
cout<<"m=";
cin>>m;
back(1);
}

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