Sunteți pe pagina 1din 24

Noiuni introductive

n mod neriguros, o mulime este o colecie bine definit de obiecte, considerat ca un


ntreg. Obiectele dintr-o mulime sunt numite elemente. Elementele unei mulimi pot fi de
orice natur: numere, persoane, litere ale alfabetului, alte mulimi, etc. Prin convenie
mulimile sunt notate cu majuscule cursive: A, B, C etc.
Mulimile nu se pot defini, dar pot fi descrise. Se descrie noiunea de mulime ca fiind
dat de mai multe elemente de acelai tip. n cadrul unei mulimi un element apare o singur
dat . De exemplu, {3, 5, 3, 2} nu este mulime pentru c elementul 3 apare de dou ori.
Dou mulimi A i B se numesc egale, i aceasta se noteaz A = B, dac dein (sunt
formate din) aceleai elemente.
A citi o mulime, nseamn a introduce elementele care o alctuiesc. Acestea sunt
memorate ntr-o variabil de tip vector. Presupunem c elementele introduse sunt distincte.











1

Generarea unei mulimi

Se consider mulimea A, constituit numai din elemente obinute dup
urmtoarele reguli:
1.1A.
2.Dac x A, atunci 2*x+1 A.
3.Dac x A, atunci 3*x+1 A.
S se scrie un program care s genereze cele mai mici n elemente ale
mulimii A.

Se genereaz n ordine cresctoare elementele mulimii ntr-un vector A i se
iniializeaz primul element al vectorului A cu 1. Plecnd de la 1 se genereaz elementele
2*1+1=3 si 3*1+1=4.
Deci, dup primul pas, elementele vectorului A sunt {1,3,4}.
Aplicnd regulile 2 i 3 pentru ultimele elemente generate, obinem elementele 2*3+1,
3*3+1, 2*4+1 si 3*4+1. Prin urmare, componentul vectorului A la pasul 2 devine
{1,3,4,7,10,9,13}.
La pasul urmtor se aplic regulile 2 i 3 ultimelor elemente generate i se obin
elementele 2*7+1, 3*7+1, 2*10+1, 3*10+1, 2*9+1, 3*9+1, 2*13+1, 3*13+1.Vectorul A
conine {1,3,4,7,10,9,13,15,22,21,31,19,28,27,40}.
La pasul x se aplic regulile 2 i 3 ultimelor elemente generate la pasul x-1.Prin
urmare, la pasul x se obin

elemente noi. Procedeul se repet pn cnd n vector obinem


n elemente.
Genernd elementele n acest mod, este posibil s obinem elemente care se repet,
prin urmare, ar trebui ca la fiecare element nou generat s fie verificat dac nu cumva exist
deja n vector elementele generate nu sunt n ordine cresctoare, deci la sfrit trebuie ca
vectorul s fie sortat i apoi s fie afiat.
Algoritmul prezentat mai sus este relativ dificil de implementat i, n plus, este i
2

neeficient ( execut aproximativ

operaii).
Generarea de la nceput a elementelor vectorului n ordine cresctoare este o idee mai bun.
Pentru aceasta, la pasul x nu se plaseaz n vector

elemente, ci se va plasa doar un singur


element(cel mai mic dintre cele care urmeaz s fie generate). Pentru a determina cel mai mic
element dintre cele care urmeaz a fi generate nu este necesar s fie determinate toate, apoi se
calculeaz minimul. Este suficient s se rein permanent dou elemente: urmtorul element
generat pe baza regulii 2 i urmtorul element generat pe baza regulii 3. Minimul va fi selectat
dintre aceste dou elemente.Pentru aceasta vor i necesari doi indici (poz2 i poz3) cu
semnificaia poz2=poziia urmtorul element pentru care se aplic regula 2, iar poz3=poziia
urmtorului element pentru care se aplic regula 3.

#include<iostream.h>
void main()
{
int n, poz2, poz3, A[1000], i, min;
cout<<"n=";cin>>n;
A[0]=1;
poz2=poz3=0;
for(i=1;i<n;i++)
{
min=2*A[poz2]+1;
if(min>3*A[poz3]+1) min=3*A[poz3]+1;
A[i]=min;
if(min==2*A[poz2]+1) poz2++;
if(min==3*A[poz3]+1) poz3++;
}
for(i=0;i<n;i++) cout<<A[i]<<" ";
cout<<endl;
}


3

Principalele operaii cu mulimi

A.Testul de apartenent
Se citete o mulime A de numere ntregi. Se citete un numr ntreg a. S se
decid dac .
Se va proceda ntr-un mod clasic. O variabil gsit va reine, iniial, valoarea 0. Apoi
se testeaz fiecare element al mulimii A dac este sau nu egal cu numrul reinut de e. n caz
de egalitate variabila gsit va reine 1. La sfrit, se va da rspunsul n funcie de coninutul
variabilei gsit.
#include<iostream.h>
void main()
{
int a[100],n,i,e,gasit;
cout<<"numarul de elemente ale multimii ";cin>>n;
for(i=1;i<=n;i++)
{ cout<<"a["<<i<<"]=";cin>>a[i];}
cout<<"elementul considerat ";cin>>e;
gasit=0;
for(i=1;i<=n;i++)
if(a[i]==e) gasit=1;
if(gasit) cout<<"elementul apartine multimii"<<endl;
else cout<<"elementul nu apartine multimii"<<endl;
}

B. Diferena a dou mulimi
Se citesc dou mulimi A i B. Se cere s se afieze mulimea C=A-B.
Se cunoate modul n care se definete diferena a dou mulimi:
C=A-B={x + ,
4

adic elementele care aparin mulimii A i nu mulimii B.
De aici rezult algoritmul: pentru fiecare element al mulimii A, se face testul dac
aparine sau nu mulimii B. n caz de neapartenena, acesta este adugat unei mulimi C,
iniial vide. O variabil k (cu valoare iniial 0) reine indicele componentei din c care va
memora urmtorul element ce se adaug mulimii diferena. n final, se tiprete c.

#include<iostream.h>
void main()
{
int a[100],b[100],c[100],n,m,i,j,k,gasit;
cout<<"numarul de elemente al multimii A ";cin>>n;
for(i=0;i<n;i++)
{cout<<"a["<<i+1<<"]=";cin>>a[i];}
cout<<"numarul de elemente al multimii B ";cin>>m;
for(i=0;i<m;i++)
{cout<<"b["<<i+1<<"]=";cin>>b[i];}
k=0;
for(i=0;i<n;i++)
{
gasit=0;
for(j=0;j<m && !gasit;j++)
if(a[i]==b[j]) gasit=1;
if(!gasit) c[k++]=a[i];
}
if(k!=0) {cout<<"A-B"<<endl;
for(i=0;i<k;i++) cout<<c[i]<<" "<<endl;}
else cout<<"A-B este vida"<<endl;
}


C. Reuniunea a dou mulimi
Se citesc dou mulimi de numere ntregi A i B. Se cere s se afieze mulimea
C= .
5

Pentru rezolvare, se rezerv trei variabile de tip tablou cu component care rein numere ntregi
(A, B ,C). Dup citirea celor dou mulimi A i B, se listeaz mulimea B, apoi A-B: de fapt,
aplicm formula: ( )
#include<iostream.h>
void main()
{
int a[100],b[100],c[200],n,m,i,j,k,gasit;
cout<<"numarul de elemente al multimii A ";cin>>n;
for(i=1;i<=n;i++)
{ cout<<"a["<<i<<"]=";cin>>a[i];}
cout<<"numarul de elemente al multimii B ";cin>>m;
for(i=1;i<=m;i++)
{ cout<<"b["<<i<<"]=";cin>>b[i];}
k=0;
for(i=1;i<=n;i++)
{
gasit=0;
for(j=1;j<=m && !gasit;j++)
if(a[i]==b[j]) gasit=1;
if(!gasit) c[k++]=a[i];
}
cout<<"A reunit cu B "<<endl;
for(i=1;i<=m;i++)cout<<b[i]<<" "<<endl;
for(i=1;i<=k-1;i++) cout<<c[i]<<" "<<endl;
}


D.Intersecia a dou mulimi
Se citesc dou mulimi de numere ntregi A i B. Se cere s se afieze mulimea

Definiia interseciei a dou mulimi:
*+
6

Pornind de la definiie, se deduce imediat algoritmul: pentru fiecare element al
mulimii A se face testul de apartenent la mulimea B, iar n caz afirmativ, este adugat la o
mulime C, iniial vid.
#include<iostream.h>
void main()
{
int a[100],b[100],c[100],n,m,i,j,k,gasit;
cout<<"numarul de elemente al multimii A ";cin>>n;
for(i=0;i<n;i++)
{ cout<<"a["<<i+1<<"]=";cin>>a[i];}
cout<<"numarul de elemente al multimii B ";cin>>m;
for(i=0;i<m;i++)
{ cout<<"b["<<i+1<<"]=";cin>>b[i];}
k=0;
for(i=0;i<n;i++)
{
gasit=0;
for(j=0;i<m && !gasit;j++)
if(a[i]==b[i]) gasit=1;
if(gasit) c[k++]=a[i];
}
if(k!=0) {cout<<"A intersectat cu B"<<endl;
for(i=0;i<k;i++) cout<<c[i]<<" "<<endl;}
else cout<<"intersectia multimilor este vida"<<endl;
}




E.Produsul cartezian dintre dou mulimi
1.Fie mulimile A={1,2,3,4,n} i B={1,2,3m} (m i n se citesc). Se cere s se
afieze mulimea C=A .
Se cunoate relaia: C=A *( ) + Exemplu: A={1,2}, B={1,2,3}. C=
*(1,1), (1,2), (1,3), (2,1), (2,2), (2,3)}. Dac se urmrete cu atenie, se observ c trebuie
7

afiate toate perechile de numere (x,y) cu x={1,2n} i y={1,2m}. Aceasta se realizeaz
foarte uor cu dou cicluri for implicate.


#include<iostream.h>
void main()
{
int m,n,i,j;
cout<<"numarul de elemente al multimii A ";cin>>n;
cout<<"numarul de elemente al multimii B ";cin>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
cout<<i<<" "<<j<<endl;
}

Problema este rezolvat pentru un caz particular (mulimea A este format din
numerele naturale cuprinse ntre 1 i n, iar mulimea B este format din numerele naturale
ntre 1 i m).
Pentru cazul general, pentru cazul n care A este o mulime format din n caractere,
iar B este o mulime format din m caractere. Se citesc elementele celor dou mulimi.
Exemplu A={a,b} i B={c,d,e}. Mulimea A are dou elemente, iar mulimea B are 3.
Algoritmul este acelai ca i n cazul anterior, pentru mulimile {1,2} i {1,2,3}. Diferena
este c, la afiare, n loc s afim perechea (i,j), afim perechea (A[i],B[j]). Astfel, n loc s
afim (1,1), afim(A[1],B[1]) adic (a,c) .a.m.d.
#include<iostream.h>
void main()
{
char multa[9],multb[9];
int n,m,i,j;
cout<<"numarul de elemente al multimii A ";cin>>n;
for(i=0;i<n;i++)
{ cout<<"mult["<<i+1<<"]=";cin>>multa[i];}
cout<<"numarul de elemente al multimii B ";cin>>m;
for(i=0;i<m;i++)
{ cout<<"mult["<<i+1<<"]=";cin>>multb[i];}
8

for( i=0;i<n;i++)
for(j=0;j<m;j++)
cout<<multa[i]<<" "<<multb[j]<<endl;
}

2. Fie n un numr natural (n>1) si L=(

) o mulime de n numere naturale


nenule. S se determine n ordine lexicografic toate elementele produsului cartezian
{1,2,

} *

+ {1,2,3

}.
Fie x=(

) si y=(

). Spunem c x preced pe y
din punct de vedere lexicografic dac exist k astfel nct

, pentru orice i<k i

<


sau k>n. De exemplu, pentru n=3 i L=(2,3,2), elementele produsului cartezian sunt:
(1,1,1), (1,1,2), (1,2,1), (1,2,2), (1,3,1), (1,3,2), (2,1,1), (2,1,2),(2,2,1), (2,2,2), (2,3,1), (2,3,2).
Se observ c produsul cartezian are



elemente.
Se reprezint un element al produsului cartezian ca un vector E cu n elemente, unde
E[i],1,2,

}.
Pentru a genera toate elementele produsului n ordine lexicografic, se aplic un
algoritm de tip succesor:
Pas 1. Iniializam vectorul E cu 1 (cel mai mic element al produsului cartezian, din
punct de vedere lexicografic).
Pas 2. Ct timp este posibil ( mai exist succesor),
-se afieaz elementul curent;
-se genereaz elementul urmtor;n acest scop, se caut prima component
(ncepnd din dreapta ctre stnga) care poate fi mrit (adic E*i+<L*i+); dac se gsete o
astfel de component,se va mri i se repune pe 1 toate componentele urmtoare; dac nu
se gasete o astfel de component, se deduce c generarea s-a ncheiat, acesta a fost cel mai
mare element din punct de vedere lexicografic.
#include<fstream.h>
#define NMax 100
void main()
{
int n, L[NMax], E[NMax], i, gata=0;
ofstream fout("pc.out");
9

cout<<"n=";cin>>n;
for(i=0;i<n;i++) {cout<<"L["<<i+1<<"]=";cin>>L[i]; E[i]=1;}
while(!gata)
{
for(i=0;i<n;i++) fout<<E[i]<<" "; fout<<endl;
for(i=n-1;i>=0 && E[i]==L[i];i--) E[i]=1;
if(i<0) gata=1;
else E[i]++;
}
fout.close();
return 0;
}



F.Submulimi
Se citete n, numr natural. Se cere s se afieze toate submulimile mulimii
{1,2,3n}.
Exemplu n=3. Mulimea {1,2,3} are urmtoarele submulimi: {1,2,3}, {1,2}, {1,3},
{2,3}, {1}, {2}, {3} i (mulimea vid).
O submulime se poate memora sub forma unei variabile de tip tablou cu n component, unde
fiecare component reine 0 sau 1. Componenta I ia valoarea 1 dac elementul i aparine
submulimii i 0 n caz contrar o astfel de reprezentare se numete reprezentare prin vector
caracteristic). Exemplu: Fie submulimea {1,2} a mulimii {1,2,3}.
1 1 0
A[1] A[2] A[3]
Avem A[1]=1, pentru c elementul 1 aparine submulimii considerate, A[2]=1, pentru
c elementul 2 aparine submulimii i A[3]=0, pentru c elementul 3 nu aparine submulimii.
Generarea tuturor submulimilor nseamn generarea tuturor combinaiilor de 0 i 1 care pot
fi reinute de vectorul A. Astfel de combinaie poate fi interpretat ca un numar natural scris
binar i pentru aceasta trebuie s generam toate numerele (n binar) care se pot reprezenta
10

utiliznd n cifre. Pornind de la 00000, se adun la fiecare pas 1, simulnd adunarea n binar.
Astfel, obinem o nou combinaie de 0 i 1 care reprezint numrul din pasul precedent la
care s-a adunat o unitate.
Algoritmul se oprete cnd a fost scris ultima combinaie 11111, care corespunde
celui mai mare numr care poate fi reinut n cele n componente. La fiecare pas se calculeaza
suma numerelor reinute de cele n componente, iar n momentul n care aceasta este n,
nseamna c au fost generate toate numerele. Exemplu: se citete n=3 i se dorete afiarea
tuturor submulimilor mulimii {1,2,3}. Se pornete de la configuraia:
A
A[1] A[2] A[3]
Se adun 1 i se obine:
A
A[1] A[2] A[3]
Aceasta configuraie reprezint numrul 1 i reprezint submulimea {3}.
Se adun 1:
A
A[1] A[2] A[3]
Configuraia reprezint numrul 2 i reprezint submulimea{2}.
Adunm 1 i obinem:

A
A[1] A[2] A[3]
Procedeul continu pn se obine configuraia:
A
A[1] A[2] A[3]
0 0 0
0 0 1
0 1 0
0 1 1
1 1 1
11

Aceasta reprezint submulimea {1,2,3} ( una ntre submulimile unei mulimi este chiar
mulimea propriu-zis). Dac ne gndim la modul n care am generat submulimile unei
mulimi cu n elemente, ajungem la concluzia c exist

submulimi ale ei (inclusiv


multimea vid).



Generarea submulimilor se poate scrie n dou moduri n c++.

1.#include<iostream.h>
void main()
{
int multa[9],n,i,s;
cout<<"numarul de elemente al multimii A "; cin>>n;
for(i=0;i<=n;) multa[i++]=0;
do
{
multa[n-1]++;
for(i=n-1;i>=1;i--)
if(multa[i]>1)
{
multa[i]-=2;
multa[i-1]+=1;
}
s=0;
for(i=0;i<n;i++) s+=multa[i];
for(i=0;i<n;i++)
if(multa[i]) cout<<i+1<<' ';
cout<<endl;
} while(s<n);
cout<<"multimea vida "<<endl;
}


2.#include<fstream.h>
#define NMax 100
void main()
12

{
int n, S[NMax], i, gata=0;
ofstream fout("subm.out");
cout<<"n=";cin>>n;
for(i=0;i<n;i++) S[i]=0;
while(!gata)
{
for(i=0;i<n;i++)
if(S[i]) fout<<i<<" "; fout<<endl;
for(i=0;i<n && S[i];i++) S[i]=0;
if(i==n) gata=1;
else S[i]=1;
}
fout.close();
}

G.Incluziunea a dou mulimi
Se citesc dou mulimi de numere ntregi A i B. Se cere s se afieze dac ntre aceste
dou mulimi exist o relaie de incluziune.
#include<iostream.h>
void main()
{
int a[100],b[100],i,j,m,n,ok,x=0;
cout<<"n=";cin>>n;
cout<<"m=";cin>>m;
for(i=1;i<=n;i++)
{
cout<<"a["<<i<<"]=";
cin>>a[i];
}
for(i=1;i<=m;i++)
{
cout<<"b["<<i<<"]=";
cin>>b[i];
}
13

for(i=1;i<=n;i++)
{
ok=0;
for(j=1;j<=m;j++)
if(a[i]==b[j]) ok=1;
if(ok==1) x++;
}
if(x==n) cout<<"Multimea A este inclusa in multimea B"<<endl;
else cout<<"Multimea A NU este inclusa in multimea B"<<endl;
}


Metoda backtracking

Metoda Backtracking se aplic problemelor n care soluia poate fi reprezentat sub
forma unui vector x = (

) S, unde S este mulimea soluiilor problemei i


S =

, i

sunt mulimi finite avnd s elemente i

R si , ()i = .
Pentru fiecare problem se dau relaii ntre componentele vectorului x, care sunt
numite condiii interne; soluiile posibile care satisfac condiiile interne se numesc soluii
rezultat. Metoda de generare a tuturor soluiilor posibile i apoi de determinare a soluiilor
rezultat prin verificarea ndeplinirii condiiilor interne necesit foarte mult timp.
Metoda backtracking evit aceast generare i este mai eficient. Elementele
vectorului x, primesc pe rnd valori n ordinea cresctoare a indicilor, x[k] va primi o valoare
numai dac au fost atribuite valori elementelor x1.. x[k-1]. La atribuirea valorii lui x[k] se
verific ndeplinirea unor condiii de continuare referitoare la x1x[k-1]. Dac aceste
condiii nu sunt ndeplinite, la pasul k, acest lucru nseamn c orice valori i-am atribui lui
x[k+1], x[k+1], .. x[n] nu se va ajunge la o soluie rezultat.
Metoda backtracking construiete un vector soluie n mod progresiv ncepnd cu
prima component a vectorului i mergnd spre ultima cu eventuale reveniri asupra
atribuirilor anterioare.
Metoda se aplic astfel :
1) se alege prima valoare S1 i I se atribuie lui x1 ;
2) se presupun generate elementele x1x[k-1], cu valori din S1..S[k-1]; pentru
14

generarea lui x[k] se alege primul element din S[k] disponibil i pentru valoarea aleas se
testeaz ndeplinirea condiiilor de continuare.
Pot aprea urmtoarele situaii :
a) x[k] ndeplinete condiiile de continuare. Dac s-a ajuns la soluia final (k =
n) atunci se afieaz soluia obinut. Dac nu s-a ajuns la soluia final se trece la generarea
elementului urmtor x [k-1];
b) x[k] nu ndeplinete condiiile de continuare. Se ncearc urmtoarea valoare
disponibil din S[k]. Dac nu se gsete nicio valoare n S[k] care s ndeplineasc condiiile
de continuare, se revine la elementul x[k-1] i se reia algoritmul pentru o nou valoare a
acestuia. Algoritmul se ncheie cnd au fost luate n considerare toate elementele lui S1.


A. Backtrackingul nerecursiv este o tehnic de programare aplicabil algoritmilor
care ofer mai multe soluii i are ca rezultat obinerea tuturor soluiilor problemei. Fiecare
soluie se memoreaz ntr-o structura de date de tip stiv implementat cu ajutorul unui
vector. Deci fiecare soluie poate fi pus sub forma unui vector.
ntr-un algoritm backtracking ne intereseaz toate soluiile posibile. Pentru a obine
fiecare soluie final se completeaz stiva nivel cu nivel trecnd astfel prin nite soluii
pariale. Astfel soluiile finale ct i cele pariale pentru a fi luate n considerare trebuie s
ndeplineasc anumite condiii numite condiii de validare. O soluie care ndeplinete o astfel
de condiie se numete soluie valid.
Toate configuraiile stivei ce reprezint soluii finale sunt alctuite din elementele
aceleiai mulimi bine definite pe care o numim mulimea soluiilor. Fiecare nou soluie
parial se obine prin completarea soluiei pariale precedente cu nc o nivel pe stiv. La
fiecare nivel se pun valori din mulimea soluiilor care nu au fost ncercate pn cnd se
obine o soluie valid. n acest moment se trece la nivelul urmtor n stiv pentru a completa
mai departe soluia relund ncercrile pe noul nivel.
La un moment dat pe un anumit nivel nu mai exist nici o valoare nencercat din
mulimea valorilor problemei. n acest caz se face un pas napoi n stiv la nivelul anterior i
se reia cutarea cu valorile rmase nencercate pe acest nivel anterior.
Respectivul nivel a mai fost vizitat dar l-am abandonat dup ce am pus o valoare care
a generat o soluie valid. Deci este posibil s fi rmas aici valori nencercate. Dac nici pe
15

acest nivel nu mai avem valori nencercate mai facem un pas napoi n stiv. Mecanismul
revenirilor a determinat denumirea de metoda backtracking.
Plecnd de la nivelul 1 i repetnd algoritmul pn cnd pe toate nivelele au fost
ncercate toate valorile din mulimea valorilor se obin soluii finale care se tipresc.
Vom implementa metoda backtracking iterativ folosind o rutin unic aplicabil
oricrei probleme. Rutina va apela proceduri i funcii care au ntotdeauna acelai nume i
parametri i care din punct de vedere al metodei realizeaz acelai lucru.
Sarcina rezolvatorului este s scrie explicit - pentru fiecare problem - procedurile i
funciile aplicate pe rutin. Astfel gsirea urmtorului element netestat de pe un nivel k al
stivei St se face cu procedura succesor (as,St,k)
Odat ales un element testarea condiiilor de validare se face cu procedura valid
(ev,St,k).Testul dac s-a ajuns sau nu la o soluie final se face cu funcia soluie (k) Soluia se
tiprete cu procedura tipar.
De asemenea fiecare nivel al stivei trebuie iniializat cu o valoare aflat naintea
tuturor valorilor posibile din mulimea soluiilor. Aceast afiare se face cu procedura init
(k,St).
Un exemplu de problema care se rezolva cu ajutorul acestei metode este generarea
partitiilor unei multimi cu n elemente date.
Definiie : Fiind dat o mulime A, submulimile
k
A A A , , ,
2 1
constituie o partiie a
acesteia dac sunt ndeplinite simultan condiiile:
1. mulimile sunt disjuncte ntre ele ( j i A A
j i
= = , | );
2.reuniunea tuturor acestor mulimi este mulimea A (

k
i
i
A A
1 =
= ).
Exemplu:
3 = n { } 3 , 2 , 1 ;
{ } 2 , 1 ; { } 3 ;
{ } 3 , 1 ; { } 2 ;
{ } 1 ; { } 3 , 2 ;
{ } 1 ; { } 2 ; { } 3 .


#include<iostream.h>
int st[10],n,k;

16

void init()
{
st[k]=0;
}
int am_succesor()
{
int i, max;
if(k==1) max=1;
else {
max=st[1];
for(i=2; i<=k-1; i++)
if(max<st[i]) max=st[i];
}
if(st[k]<max+1 && st[k]<k)
{
st[k]++;
return 1;
}
else return 0;
}
int e_valid()
{
return 1;
}
void afisare()
{
int i,j,max;
max=st[1];
for(i=2; i<=n; i++)
if(max<st[i]) max=st[i];
for(i=1; i<=max; i++)
{
for(j=1; j<=n; j++)
if(st[j]==i) cout<<j;
cout<<" ";
}
cout<<endl;
17

}
void back()
{
int as;
k=1; init();
while(k>0)
{
do{}while((as=am_succesor()) && !e_valid());
if(as)
if(k==n) afisare();
else { k++; init(); }
else k--;
}
}
void main()
{
cout<<"n= "; cin>>n;
back();
}

Un alt exemplu de problem care se rezolv folosind backtrackingul nerecursiv este generarea
mulimii produsului cartezian.

#include<iostream.h>
#include<conio.h>
int st[10],n,k,card[10];

void init()
{
st[k]=0;
}
int am_succesor()
{
if(st[k]<card[k])
{
st[k]++;
return 1;
}
18

else return 0;
}
int e_valid()
{
return 1;
}
void afisare()
{
for(int i=1; i<=k; i++)
cout<<st[i];
cout<<endl;
}
void back()
{
int as;
k=1; init();
while(k>0)
{
do{}while((as=am_succesor()) && !e_valid());
if(as)
if(k==n) afisare();
else { k++; init(); }
else k--;
}
}
void main()
{
int i;
cout<<"n= "; cin>>n;
for(i=1; i<=n; i++)
{
cout<<"card["<<i<<"]= ";
cin>>card[i];
}
back();
getch();
}
19





Backtrackingul recursiv este o tehnic de programare care gsete o soluie,
membr a produsului cartezian a n mulimi (dac punem un X pe o stiv de h elemente,
evident n mulimi corespunde la o stiv de h elemente, unde n=h). Dac mulimea X are m
elemente corespunde la o lime l a stivei unde h=m. I de pe stiv se plimb de la 1 la m, sau
de la 1 la l. Pentru a parcurge stiva de la 1 la h se apeleaz recursiv funcia back_r, o funcie
recursiv. Pentru a parcurge n lime mulimea de pe nivelul k al stivei, avem cte un ciclu
for pentru fiecare apelare a funciei recursive back_r. Aceste cicluri trebuie parcurse
independent, de aceea contorul (n sursele noastre i) trebuie declarat local n funcia back_r, i
se aloc pe stiv. Dac i este declarat global, buclele for nu vor funciona independent.
Cel mai simplu exemplu este produsul cartezian:Se consider n mulimi
n
M M M , , ,
2 1
.
Mulimile au un numr finit de elemente: ( )
1 1
M card c = , ( )
2 2
M card c = , ,
( )
n n
M card c = . S se genereze mulimile produsului cartezian
n
M M M
2 1
.
#include<iostream.h>
int a[10],p[10],n,i;
void afiseaza()
{
for(int i=1; i<=n; i++)
cout<<p[i];
cout<<endl;
}
void prod_cartezian(int pas, int n)
{
int i;
if(pas==n+1) afiseaza();
else
for(i=1; i<=a[pas]; i++)
{
p[pas]=i;
prod_cartezian(pas+1,n);
}
}
20

void main()
{
cout<<"numarul de multimi= "; cin>>n;
for(i=1; i<=n; i++)
{
cout<<"nr. de elem. al multimii "<<i<<"= ";
cin>>a[i];
}
prod_cartezian(1,n);
}




21


Bibliografie


- Emanula Cerchez, Marinel erban Programarea n
limbajul C++pentru liceu (partea I ), Editura Polirom,
2005
- George Daniel Mateescu, Pavel Florin Moraru -
Informatica pentru liceu i bac .Editura Donaris.2005
- Tudor Sorin Manual pentru clasa a X-a.Editura
L&S INFORMAT.
- Doina Logofatu - Algoritmi fundamentali in C++.
Editura Polirom









22






Cuprins



1.Noiuni introductive1
2.Generarea unei mulimi..2
3.Principalele operaii cu mulimi.6
A.Testul de apartenen .4
B.Diferena a dou mulimi4
C.Reuniunea a dou mulimi.5
D.Intersecia a dou mulimi.6
E.Produsul cartezian dintre dou mulimi.7
F.Submulimi10
G.Incluziunea a dou mulimi..13
4.Metoda backtracking..14
A.Backtrackingul nerecursiv15
B.Backtrackingul recursiv..21
5.Bibliografie...22

23

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