Documente Academic
Documente Profesional
Documente Cultură
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
} *
+ {1,2,3
}.
Fie x=(
) si y=(
). Spunem c x preced pe y
din punct de vedere lexicografic dac exist k astfel nct
<
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
, 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