Sunteți pe pagina 1din 77

ALGORITMI POLINOMIALI DE GENERARE A

SUBMULŢIMILOR DISCRETE FINITE

Cuprins:
- - Introducere - - ............................................................................................................ 5

- - Prezentare detaliată - -

I. Algoritmi polinomiali de gerenare a submulţimilor discrete finite


I.1. Reprezentarea mulţimilor şi generarea iterativă a elementelor .................................

I.2. Generarea elementelor unui produs cartezian ...........................................................

I.3. Generarea tuturor submulţimilor unei mulţimi .........................................................

I.4. Generarea combinărilor .............................................................................................

I.5. Generarea permutărilor .............................................................................................

1
I.6. Generarea aranjamentelor ......................................................................................... 11

I.7. Generarea combinărilor cu repetiţie .......................................................................... 19

I.8. Generarea partiţiilor unui număr natural ................................................................... 24

I.9. Relaţii binare. Închiderea tranzitivă .......................................................................... 40

I.10. Generarea partiţiilor unei mulţimi finite ................................................................. 43

- - Prezentarea aplicaţiei - - 46

1. Reprezentarea mulţimilor şi generarea iterativa a elementelor ........................... 55

1.1. Noţiuni teoretice ....................................................................................................... 57

1.2. Algoritm de generare ................................................................................................

2. Generarea elementelor unui produs cartezian........................................................ 60

2.1. Noţiuni teoretice ....................................................................................................... 60

2.2. Algoritm de generare ................................................................................................ 61

2.3. Analiza algoritmului ................................................................................................ 62

3. Generarea tuturor submulţimilor unei mulţimi ..................................................... 62

3.1.1. Noţiuni teoretice .................................................................................................... 63

3.1.2. Algoritm de generare ............................................................................................. 64

3.2.1. Noţiuni teoretice .................................................................................................... 65

7 65

9 65

2
66

3.2.2. Algoritm de generare .............................................................................................

3.3.1. Noţiuni teoretice ....................................................................................................

3.3.2.1. Algoritm de generare .......................................................................................... 67

3.3.2.2. Analiza algoritmului ........................................................................................... 68

3.4.1. Noţiuni teoretice .................................................................................................... 71

3.4.2. Algoritm de generare ............................................................................................. 71

4. Generarea aranjamentelor ....................................................................................... 72

4.1.1. Noţiuni teoretice .................................................................................................... 73

4.1.2. Algoritm de generare ............................................................................................. 74

4.2.1. Noţiuni teoretice .................................................................................................... 74

4.2.2. Algoritm de generare ............................................................................................ 74

- - Concluzii finale - - ………………………………………………………………… 75

- - Bibliografie - - ……………………………………………………………………... 75
77

78

-Introducere-

3
Motivul alegerii acestei lucrări este de a înţelege mai bine cum un algoritm matematic
de generare poate fi implementat în cadrul unui limbaj de programare.

Algoritmul propriu-zis este înglobat în cadrul unui program întreg ce este format din
anumite biblioteci pentru diferite tipuri de proceduri sau funcţii prestabilite, constante sau
variabile de date şi numeroase modalităti de prelucrare a datelor de intrare. Acestea pot fi
primite de la tastatura sau direct dintr-un anumit fişier.

La final se poate observa soluţia generată în urma rulării respectivului algoritm în


compilator, în cazul de faţă acesta fiind Borland C++ 3.1.

Această lucrare este intitulată “Algoritmi polinomiali de generare a submulţimilor


discrete finite” şi face parte din “GENERAREA DE SUBMULŢIMI”. Este structurată în
zece subcapitole, iar fiecare dintre acestea se axează pe o anumită modalitate de generare a
elementelor unei mulţimi. Pentru reprezentarea unei mulţimi se foloseşte de obicei un vector
cu n componente în care se introduc elementele acesteia.

Submulţimile generate vor fi de următoarele două tipuri:

- submulţimi în care este importantă ordinea în care apar elementele;

- submulţimi în care nu contează ordinea în care apar elementele.

Toate generările ce sunt prezentate în această lucrare au un caracter iterativ, fiecare


element fiind dedus din anteriorul său

La generarea elementelor produsului cartezian din cadrul aplicaţiei elementele vor fi


generate succesiv într-un vector V cu m componente.

În următorul subcapitol sunt prezentate 4 metode de generare a tuturor submulţimilor


unei mulţimi cu n elemente.

În cadrul generării combinărilor se va studia problema generării tuturor celor


submulţimi ale lui A, cu proprietatea că oricare două submulţimi diferă prin natura
elementelor.

Subcapitolul 5 prezintă mai multe metode de a genera cele n! permutări de grad n.


Orice permutare de grad n se reprezintă printr-un vector p cu n componente.

La generarea aranjamentelor se vor descrie două metode de generare a tuturor


grupărilor de m elemente distincte din mulţimea [n], două grupări diferind fie prin natura, fie
prin ordinea elementelor.

Generarea combinărilor cu repetiţie conţine trei metode de generare a m-combinărilor


cu repetiţie.

4
În subcapitolul următor se prezintă determinarea tuturor modalităţilor de scriere a
unui numar n sub forma :

n= + + ... +

unde numerele naturale nenule , ..., se numesc părţi ale lui n.

La final se generează toate partiţiile unei mulţimi, unde o partiţie reprezintă o


descompunere a mulţimii de forma :

A= ∪ ∪…∪

unde cele k submulţimi , …, (numite clase) sunt nevide şi două câte două disjuncte.

Aplicaţia propriu-zisă este compusă din două programe rulate în Borland C++.

Prima problemă generează elementele unui produs cartezian. Elementele produsului


cartezian vor fi generate succesiv într-un vector V cu m componente.

În cadrul celui de-al doilea program se implementează un algoritm de generare a


tuturor grupărilor de m elemente distincte din mulţimea [n], două grupări diferind fie prin
natura lor, fie prin ordinea elementelor. Astfel se generează aranjamente de n elemente luate
câte m, cu repetiţie.

ALGORITMI POLINOMIALI DE GENERARE A


SUBMULŢIMILOR DISCRETE FINITE

5
I.1. Reprezentarea mulţimilor şi generarea iterativă a
elementelor

Fie A = { ,...., } o mulţime oarecare cu n elemente. Pentru reprezentarea ei se


foloseşte de obicei un vector cu n componente în care se introduc elementele mulţimii. Este
important de notat că o astfel de asociere mulţime → vector stabileşte implicit o ordine a
elementelor mulţimii, corespunzătoare ordinii în care apar elementele în vector.

Fie B o submulţime a lui A. Există mai multe modalitaţi de reprezentare a


submulţimilor, cele mai folosite fiind următoarele:

(i) - printr-un vector cu n componente, unde elementele submulţimii sunt plasate


la începutul vectorului, precizându-se în plus numărul lor sau introducând pe
restul poziţiilor din vector o valoare care nu aparţine mulţimii A = [n] =
{1,2,...,n}.

(i’) - printr-un vector cu n componente, construit analog cu cel din reprezentarea (i)
cu deosebirea că elementele submulţimii sunt plasate la sfarşitul vectorului.

(ii) - prin vectorul caracteristic al submulţimii, adică acel vector c {0,1 definit
de:

c(i) = (1)

În această lucrare vom presupune totdeauna că A = [n] = {1,...,n} deoarece între o


orice mulţime A={ ,...., } şi [n] există o bijecţie, de exemplu cea dată de corespondenţa
.

Submulţimile care vor fi generate în această lucrare vor fi de urmatoarele două tipuri:

- submulţimi în care este importantă ordinea în care apar elementele.

- submulţimi în care nu conteaza ordinea în care apar elementele.

6
Pentru submulţimile de al doilea tip, dacă folosim pentru ele una dintre reprezentările
(i) sau (i’), vom conveni că ordinea în care apar elementele să fie cea crescătoare; în acest
mod vom evita generarea de mai multe ori a aceleaşi submulţimi.

Toate generările ce vor fi prezentate vor avea un caracter iterativ, fiecare element
fiind dedus din anteriorul său. Algoritmul general de construire a unui nou element apare în
procedura GEN. El foloseşte pe langă un vector V de dimensiune n ( în care vor fi generate
succesiv submulţimile ) şi un indicator de generare IG. La apelarea procedurii, IG are fie
valoarea 0 ( dacă este vorba de prima apelare, deci trebuie făcuta o iniţializare ), fie valoarea
1 ( dacă trebuie construit succesorul vectorului V ). La terminarea fiecărei execuţii a
procedurii, IG are fie valoarea 1 ( dacă a fost generat un nou vector V ), fie valoarea 0 ( dacă
au fost generaţi toţi vectorii V ceruţi de problema concretă ).

procedure GEN(V , n , IG)

array V(n)

IG 1; return

endif

if [exista succesor al lui V] then V [ succesorul lui V]

else IG 0

endif

return

end

O secventă tipică de instrucţiuni care realizează generarea şi prelucrarea tuturor


vectorilor V cu o anumită proprietate este următoarea:

do

call GEN (V , n , IG)

if IG = 0 then exit

endif

call PREL (V, n)

repeat

7
Procedura PREL asigură efectuarea unei anumite prelucrări pe baza vectorului V
curent, fără însa a modifica vreun element al sau.

În mulţi dintre algoritmii care vor fi prezentaţi, vectorii vor fi generaţi în ordine
lexicografică crescătoare. Este de remarcat faptul că aceasta corespunde strategiei
backtracking de construcţie a algoritmilor.

I.2. Generarea elementelor unui produs cartezian

Fie date m mulţimi ,...., unde pentru fiecare i {1 , ... , m}, =[ ]={1,
2 , ... , }. Se pune problema generarii tuturor celor elemente ale produsului
cartezian x x ... x .

Elementele produsului cartezian vor fi generate succesiv într-un vector V cu m


componente. Vectorii vor fi generaţi conform ordinii lexicografice crescătoare. Drept urmare,
se pleacă de la vectorul (1 , 1 , ... , 1). Pentru a construi seccesorul unui vector V se
procedează în modul următor: se determină cel mai mare indice i cu şi drept
succesorul al lui V se alege vectorul ( , ..., , +1, 1, ..., 1). Dacă un astfel de indice i nu
există , înseamnă că vectorul V curent este ( , , ... , ), care este cel mai mare in ordine
lexicografică şi deci procesul de generare s-a incheiat. Determinarea indicelui i se face
parcurgând elementele lui V în ordine inversă. Drept urmare se obţine procedura
PRODCART.

procedure PRODCART ( V , m , n , IG )

integer V(m), n(m)

if IG = 0 then for i = 1, m

V(i) 1

repeat

IG 1 ; return

endif

8
for i = n , 1 , -1

if V(i) < n(i) then V(i) V(i) +1 ; return

else V(i) 1

endif

repeat

IG 0 ; return

end

Un caz particular al problemei tratate este cel în care = = = ... = =n,


deci când trebuie generate elementele mulţimii [n , elemente care mai poartă numele de m-
combinaţii a n elemente . Evident numărul lor este .

Pentru a obţine numărul de calcule efectuat de algoritmul PRODCART , observăm că


pentru , ... , fixate, componenta îşi schimbă valoarea (mărindu-se cu o unitate sau
devenind 1) de ori, deci în total îşi schimbă valoarea de * * ... * ori. Drept
urmare tinănd cont şi de iniţializare, numărul instrucţiunilor de atribuire referitoare la
elementele vectorului V este m + + + ... + *...* . În cazul particular = = ...
= = n numărul acestor operaţii de atribuire este m + n + + ... + =m+n =
= ( ).

Pe de altă parte, pentru fiecare , ... , fixate , creşte cu o unitate de -1 ori,


fiecare asemenea creştere fiind precedată de cele m − i + 1 comparări ale componentelor
,..., cu limitele superioare , ... , . Deci numărul de comparări referitoare la
componentele vectorului V este , la care se
adaugă cele m comparări care conduc la IG = 0. În cazul particular = = ... = =n
numărul acestor comparări este

(n - 1) = ( n - 1) + m=
=

Este de remarcat legătura între algoritmul prezentat şi sistemele mixte de numeraţie.


Un sistem mixt de numeraţie este definit de o infinitate de numere naturale , , ... , mai
mari sau egale cu 2, numite baze ale sistemului. Orice număr natural N se reprezinta în mod
unic sub forma

N= + + + + ... +

9
unde 0 pentru orice i , iar 0 dacă N 0.

În particular să consideram submulţimea A = {0, 1, ..., ... − 1} de numere


naturale şi sistemul de numeraţie mixt cu bazele , ..., . Atunci orice număr N din A se
poate scrie unic sub forma :

N= ... + ... + ... + + (3)

unde 0 < , i = 1, 2, ..., m. În acest mod se stabileşte o corespondenţa biunivocă

:A [ ] [ ] ... [ ] ce este dată de :

(N) = ( + 1, ... , + 1) (4)

Se observă cu uşurinţa că procedura PRODCART generează vectorii V = ( , ... , )


astfel încât valorile ( - 1, ... , - 1) corespund în ordine numerelor naturale 0,1,...,
*..* - 1.

I.3. Generarea tuturor submulţimilor unei mulţimi

Vor fi prezentate 4 metode de generare a tuturor submulţimilor unei mulţimi cu n


elemente.

Prima metodă foloseşte pentru reprezentarea submulţimilor vectorul caracteristic.


Drept urmare, problema enunţata se rezumă la a genera toţi vectorii V . Algoritmul
respectiv, construit cu procedura SUBM1, se deduce cu uşurinţa din procedura PRODCART.

procedure SUBM1 (V, n, IG)

integer V(n)

10
if IG = 0 then for i = 1, n

V(i) 0

repeat

IG 1 ; return

endif

for i = n, 1, -1

if V(i) < 1 then V(i) 1; retunr

else V(i) 0

endif

repeat

IG 0 ; return

end

Conform observaţiei făcute anterior, se observă că valorile ataşate


vectorilor V sunt , în ordinea generării, tocmai numerele naturale 0, 1, ..., − 1.

O a doua metodă urmăreşte să genereze submulţimile în ordinea crescătoare a


numărului lor de elemente. Se va folosi reprezentarea (i’) a submulţimilor, ţinând cont şi de
faptul că nu interesează ordinea elementelor în submulţime; conform convenţiei făcute,
elementele vor apărea în vector în ordine crescătoare.

Evident, se pleacă de la vectorul V = (0, ..., 0) corespunzător mulţimii vide. Vectorii


vor fi generaţi de asemenea conform ordinii lexicografice crescătoare. Fie V = ( , ... , )
un vector căruia dorim sa îi determinăm succesorul. Pentru aceasta vom determina acel
indice i care satisface relaţiile :

< i; = i+1; ...; = n 1; =n (5)

11
Este evident că cel mai mic vector mai mare decât V conform ordinei lexicografice
este vectorul următor :

( , ..., , + 1, + 2, ..., + n - i + 1) (6)

care se obţine din V mărind pe cu o unitate, iar pe fiecare dintre elementele aflate la
dreapta lui se determină din precedentul prin mărirea acestuia cu o unitate.

Dacă nu există un indice i satisfăcând relaţiile (5), înseamnă că v = (1, 2, ..., n) deci au
fost generate toate submulţimile.

Procedura care concretizează metoda descrisă este procedura SUBM2.

procedure SUBM2 ( V , n , IG)

integer V(n)

if IG = 0 then for i = 1, n :

V(i) 0

repeat

IG 1; return

endif

for i = n , 1, -1 :

if V(i) < i then V(i) V(i) + 1

for j = i + 1, N

V(j) V(j 1) +1

repeat

return

endif

repeat

IG 0; return

end

12
Nu vom analiza timpul cerut de acest algoritm.

Observaţie. Trecerea la o submulţime având un element mai mult decât cea


precedentă corespunde la schimbarea valorii unui element din 0 în 1. Algoritmul poate fi
modificat fără dificultate pentru a pune în evidenţa aceste treceri.

A treia metodă de generare a tuturor submulţimilor unei mulţimi foloseşte, la fel ca


prima metodă, reprezentarea submulţimilor cu ajutorul vectorului caracteristic. Deosebirea
constă în faptul că la fiecare trecere de la un vector V {0, 1 la următorul va fi modificată o
singură componentă.

Se numeşte cod Gray o secvenţă G(n) de vectori distincţi din {0, 1 , începând cu
( 0, ..., 0 ) şi astfel încât doi vectori succesivi diferă pe o singură poziţie. G(n) se reprezintă
sub forma matricii (7) cu linii şi n coloane, unde G(1) este dat de (8).

G(n) (7) G(n + 1 ) = (9)

G(1) (8)

Codul G(n 1) se poate obţine din codul G(n) construind matricea corespunzătoare în
modul ilustrat în (9). După cum se recunoaşte uşor, se respectă condiţia ca două linii să difere
pe o singură poziţie.

Ştiind că prima linie din G(n) este (0, ..., 0) , codul G(n) este bine determinat de un
vector cu componente, unde pentru fiecare i {1, ..., }, este poziţia pe
care diferă liniile i şi i 1 din G(n), cu menţiunea că poziţiile ocupate de biţii 0 şi 1 sunt
numerotate de la dreapta la stânga. Din matricea (9) , interpretată ca relaţie între codurile
G(n) şi G(n ), rezultă că dacă ( , , ..., ), atunci :

13
(10)

Relaţiile (10) permit să deducem uşor prin inducţie după n că vectorul obţinut din
prin inversarea ordinei elementelor sale este tot . Ca urmare, relaţiile (10) se pot scrie
condensat sub forma :

(10’)

Exemplu. Pentru n = 3 , avem :

G(3) =

,1)

= (1, 2, 1, 3, 1, 2, 1)

Plecând de la relaţiile (10’), vectorului îi putem asocia un arbore binar strict, cu n


nivele, astfel încât pentru orice i {1, ..., n}, vârfurile situate pe nivelul i sunt etichetate cu
n + 1 i. Acest arbore are proprietatea că etichetele vârfurilor arborelui, considerate în
inordine, formează tocmai vectorul . De exemplu pentru n 4, se obţine arborele din
figura I.1.

3 3

2 2 2 2

1 1 1 1 1 1 1 1

Fig. I.1

14
i

i-1

i-2

Fig I.2

Se observă că acest arbore nu trebuie construit explicit pentru a-l parcurge în inordine.
Mai mult, iniţial putem introduce într-o stivă, în ordine de la bază la vârf, elementele
n, n − 1, ..., 1. La fiecare pas se va scoate un element din stivă ( dacă stiva este vidă, procesul
se încheie ), element care constituie poziţia ce trebuie modificată pentru a obţine următoarea
linie din G(n); dacă acest element este i >1, atunci se vor introduce în stivă pe rînd elementele
i − 1, i − 2, ..., 2, 1, în conformitate cu algoritmul de parcurgere în inordine şi cu figura I.2.
Mai observăm că putem reveni la numerotarea uzuală a poziţiilor ( de la stânga la dreapta ),
deoarece aceasta implică doar inversarea ordinii în care apar elementele liniilor din G(n).

Observaţiile de mai sus duc la procedura GRAY1, în care cei vectori căutaţi se
obţin succesiv în vectorul V.
procedure GRAY1 ( n, V, ς, IG )
integer V(n) ; stack ς

if IG = 0 then ς

for i = n, 1,-1

V(i) 0; i ς

repeat
IG ← 1; return
endif

if ς = then IG ← 0; return

endif

i ς; V(1) 1 V(i)

for j i 1, 1, 1

j ς
repeat

15
return
end
Procedura GRAY1 mai poate fi îmbunătaţită prin eliminarea ultimului ciclu for, ceea
ce va face ca trecerea de la un vector V la următorul să necesite un timp constant. În acest
scop, stiva ς va fi înlocuită cu un vector SUB cu n componente cu următorul conţinut:
- dacă elemetul i se află în stivă, atunci SUB(i) este elementul aflat în stivă imediat sub el
- dacă elementul i nu se află în stiva, atunci SUB(i) = i + 1, corespunzător faptului că în
momentul în care va fi introdus în stivă, sub el se va afla i + 1.
Drept urmare se obţine procedura GRAY2 în care i este elementul din vârful stivei.

procedure GRAY2 ( n, V, SUB, i, IG)


integer V(n), SUB(n)
if IG = 0 then for j = 1, n

V(j) 0; SUB(j) j+1

repeat

i 1; IG 1; return
endif

if i = n + 1 then IG 0; return

endif

V(i) 1 V(i)

if i = 1 then i SUB(1); SUB 2

else SUB(i 1) SUB(i); SUB(i) i + 1; i 1

endif
return
end

Conţinutul ultimei instrucţiuni if din procedura GRAY2 poate fi uşor înteles dacă se
urmăreşte figura I.2.
O ultimă metodă foloşeste reprezentarea (i) a submulţimilor, păstrându-se în variabila
k numărul elementelor. Elementele submulţimii vor apărea în ordine crescătoare, adică

16
< < ...< . Iniţial k = 0. La pasul următor vom lua k = 1 şi = 1. În continuare,
vectorii vor fi generaţi conform ordinei lexicografice crescătoare. În consecinţă, trecerea de la
un vector V = ( ) la succesorul său se va face astfel:

- dacă < n, atunci succesorul va fi ( , + 1)

- dacă = n, sunt posibile două situaţii : dacă k > 1, atunci succesorul căutat este (
+ 1 ); dacă k = 1, s-a ajuns la V = (n) şi deci au fost generate toate
submulţimile.
Spre deosebire de a doua metodă, submulţimile nu mai sunt generate în ordinea
crescătoare a numărului lor de elemente. Este însă important de observat că trecerea de la un
vector la succesorul său necesită timp constant. Procedura corespunzătoare metodei descrise
este procedura SUBM3.

procedure SUBM3(V, n, IG, k)


integer V(n)

if IG = 0 then k 0; IG 1; return

endif

if k = 0 then k 1; V(1) 1; return


endif

if V(k) < n then k k + 1; V(k) V(k) + 1; return

endif

if k = 1 then IG 0; return

else k k 1; V(k) V(k) + 1; return


endif
return
end

I.4. Generarea combinărilor

17
Fie A = [n] = {1,2, ...,n} şi m [n]. Vom prezenta problema generării tuturor celor
submulţimi ale lui A, cu proprietatea că oricare două submulţimi diferă prin natura
elementelor. O astfel de submulţime se numeşte m-combinare a n elemente.
O primă metodă foloseşte pentru submulţimi reprezentarea (i). Dat fiind că valoarea
m este cunoscută, se va folosi un vector V cu m componente, fiecare conţinând un element al
mulţimii A. Deoarece în cadrul submlţimii ordinea elementelor nu prezintă importanţă, se vor
genera ca de obicei toţi vectorii V = ( , ..., ) satisfăcâd relaţiile:

1 < < ... < n

Vectorii vor fi generaţi în ordine lexicografică. Se pleacă de la vectorul (1,2, ..., m).
Fiind dat un vector V = ( , ..., ), vectorul care îi urmează imediat în ordine lexicografică
se determină astfel :

- se determină indicele i satisfăcând relaţiile :

<n m + 1; =n m + i + 1, ..., =n 1; =n (11)

- se trece la vectorul

( , ..., , + 1, + 2, ..., +n i + 1) (12)

Dacă nu există un indice i satisfăcând relaţiile (11), înseamnă că vectorul V conţine în


ordine elementele n m + 1, n m + 2, ..., n; deci au fost generate toate m-combinările.
Astfel reiese procedura COMB1.

procedure COMB1 (V, n, m, IG)

integer V(m)

if IG = 0 then for i = 1, m

18
V(i) ← 1

repeat

endif

for i = m, 1, 1

if V(i) < n m + i then V(i) ← V(i) + 1

for j = i + 1, m

V(j) V(j 1) + 1

repeat

return

endif

repeat

IG 0; return

end

În continuare analizăm timpul cerut de algoritm. Condiţia <n m + i din relaţiile


(11) revine la {i, i + 1, ..., n m+i 1. Pentru fiecare astfel de , elementele , ...,
se pot alege (crescător) în moduri. Rezultă că relaţiile (11) sunt verficate de un
număr de ori egal cu

= + + ...+ (13)

Aplicând formula

+ + ...+ = (14)

rezultă că relaţiile (11) sunt verificate de ori.

19
Pentru a determina că suntem in situaţia (11) se fac comparari ale lui , , ...,
deci m i + 1 comparări. Instrucţiunea de atribuire v(i) ← v(i) + 1 împreună cu ciclul for
care îi urmează necesită m i + 1 atribuiri. Rezultă că ori de câte ori ajungem în situaţia (11)
sunt necesare 2( m i + 1) atribuiri + comparări referitoare la elementele vectorului V.

Ţinând cont de faptul că i poate lua oricare valoare 1, 2, ..., m, rezultă că algoritmul
prezentat necesită un număr de operaţii (comparări + atribuiri) referitoare la elementele lui V
egal cu 2N unde :

N = =m + (m 1) + ... + 2 +
= + + ... + + + + + ... +
+ ...........+ + +

Aplicând repetat formula (14), se obţine:

N=( 1) + ( 1) +...+ ( 1) + ( 1) = m 1 (15)

Astfel se obţine că pentru generarea tuturor m-combinărilor a n elemente sunt


necesare 2( m 1) operaţii de atribuire şi comparare asupra elementelor vectorului V
(exceptând iniţializarea). Deci timpul necesitat de algoritm este de ordinul ( ) unde
= min(m, n m + 1).

A doua metodă pentru generarea tuturor celor m-combinări a n elemente foloseşte


pentru fiecare m-combinare (submulţime cu m elemente a lui [n]) reprezentarea prin vectorul
caracteristic.

Din nou vectorii V vor fi generaţi în ordine lexicografică, deci conform strategiei
generale backtracking. De aceea vom pleca de la vectorul (0, ..., 0, 1, ..., 1) în care primele
n m componente sunt egale cu 0, iar următoarele m elemente sunt egale cu 1. Fie acum V
un vector oarecare pentru care se cere să se determine succesorul. Se observă că este util să
punem în evidenţă ultima secvenţă de elementele egale cu 1 (fig I.3).

V = (........., 0, 1, .........., 1, 0, ........, 0)


↑ ↑
A B

Fig I.3

Această ultimă secvenţă de elemente egale cu 1 este bine determinată de perechea de


numere naturale (A, B) având semnificaţia următoare:

20
B = poziţia ultimului element egal cu 1

A = poziţia elementului egal cu 0 situat imediat la stângă ultimei secvenţe de elemente


egale cu 1.

Trecerea la următorul vector V (conform ordinei lexicografice crescătoare) se face


diferenţiat după cum ultima secvenţă de 1 este formată dintr-un singur element egal cu 1 sau
din mai multe:

Cazul 1. ( A + 1 < B). În cazul acesta, notând cu =B A numărul de elemente din


ultima secvenţă de 1, iar prin numărul de elemente finale egal cu 0 (unde , 0),
trecerea de la V la succesorul său V’ este ilustrată în figura I.4.

α β

V=(....,0,1,1,....,1,0,....,0)

A B

V’ = (. . . . , 1 , 0 , 0 , . . . . , 0 , 1 , . . . . , 1 )

A β α-1 B

Fig I.4

Aceasta arată că V(A) şi V(A +1) primesc respectiv valorile 1 şi 0. În plus, ordinea
ultimelor + 1 elemente este inversată. Pentru ca acestă inversiune să fie realizată mai
rapid, se notează prin = min( 1, ); atunci este suficient ca primele elemente care
urmează lui V(A 1) să primească valoarea 0, iar ultimele elemente ale vectorului V să
primească valoarea 1. În plus, noile valori pentru A şi B sunt respectiv n + 1 + A B şi n.

Cazul 2 (A + 1 = B). În acest caz trecerea de la V la succesorul său V’ se realizează


prin atribuirile V(A)←1 şi V(A + 1)←0. Noua valoare a lui B va fi A, iar noua valoare a lui A
va fi cel mai mare indice mai mic decât A pentru care elementul corespunzător este 0 :

V = (... 0, 1, 0, ..., 0)

V’ = (... 1, 0, 0, ..., 0)

Memorarea şi actualizarea indicilor A şi B scurtează timpul de calcul. Într-adevăr, are


loc o căutare numai în situaţia în care A + 1 = B.

Procedura corespunzătoare metodei descrise este procedura COMB2.

procedure COMB2(V, n, m, IG, A, B)

integer V(n)

21
if IG = 0 then for i = 1, n m

V(i)←0

repeat

for i = n m + 1, n

V(i)←1

repeat

IG←1; A←n m; B←n; return

endif

if A = 0 then IG←0; return

endif

if A + 1 < B then V(A)←1; V(A+1)←0; ←min(B A 1, n B)

for i = 1,

V(A+1+i)←0; V(n+1 i)←1

repeat

(A,B)←(A+1+n B, n); return

else V(A)←1; V(A+1)←0; B←A; A←A 1

while A>0

if V(A) = 0 then return

else A←A 1

endif

repeat

return

endif

Se observă că în procedură , IG a primit valoarea 0 dacă A = 0, adică dacă V = (1, ...,


1, 0, ..., 0), care este ultimul vector conform ordinei lexicografice, cu m elemente egale cu 1.

22
I.5. Generarea permutărilor

Sunt prezentate mai multe metode de a genera cele n! permutări de grad n. Există o
foarte mare varietate de astfel de metode, problema în sine pretindându-se la rezolvări foarte
ingenioase. Din păcate, indiferent de algoritm, timpul necesar este cel puţin de ordinul O(n!)
ceea ce face ca timpul să crească vertiginos odată cu n şi drept urmare este indicat ca pentru
rezolvarea unei probleme, ce iniţial necesită generarea tuturor permutărilor de grad n, să
căutăm alte soluţii; un exemplu tipic îl constituie calculul unui determinant. Cum metodele
care vor fi prezentate nu au un nume bine precizat în literatura de specialitate, le vom
numerota pur şi simplu.

Orice permutare de grad n se reprezintă printr-un vector p cu n componente.

Metoda 1. Constă în a genera permutările conform ordinii lexicografice crescătoare.


Se pleacă de la permutarea identică (1, 2, ..., n) care este evident cea mai mică în ordine
lexicografică.

Fie construită o permutare p = ( , ..., ). Pentru determinarea permutării p’ care îi


urmează în ordine lexicografică se pune în evidenţă acel indice i satisfăcând relaţiile

< (16)

Atunci este evident că trebuie modificat. Cum p’ urmează imediat după p, trebuie
înlocuit cu cel mai mic dintre elemente , ..., cu proprietatea că este mai mare decât ;
fie el . Schimbând pe cu se ajunge la vectorul

( ) (17)

în care ultimele n i elemente apar în ordine descrescătoare. În consecinţă p’ se obţine din


vectorul (17) inversând ordinea ultimelor n i componente.

Astfel rezultă procedura PERM1.

procedure PERM1 (p, n, IG)

23
integer p(n)

if IG = 0 then for i = 1, n

p(i)←i

repeat

IG←1; repeat

endif

i←n 1

while >

i←i 1

if i = 0 then IG←0; return

endif

repeat

k←n

while >

k←k 1

repeat

↔ ; m←

for j = 1, m

repeat

return

end

Pentru evaluarea timpului cerut de execuţia acestui algoritm, vom calcula numărul
de interschimbări şi numărul de comparări între elementele vectorului p.

24
Pentru fiecare dintre cele n valori posibile ale lui , se execută interschimbări în
vederea calculul celor (n 1)! permutări ale mulţimii [n] \ { }. În plus, fiecare dintre cele
n -1 treceri ale lui de la o valoare la valoarea imediat următoare se face printr-o
interschimbare ↔ urmată de încă interschimbări,adică interschimbări. Se
obţine astfel următoarea formulă de recurenţă :

(18)

Fie = + (19)

Atunci din (18) se deduce

=n +n .

adică

= n( + ) cu = (20)

şi cu condiţia iniţială = 1.

Se verifică uşor că din (20) se obţine :

S = n! (21)

Ţinând cont că

=( = 1,543.

rezultă că 1,543 n!

25
Pentru calculul valorilor { } se precedează analog. Pentru fiecare dintre cele n valori
ale lui , se execută comparări pentru calculul celor (n 1)! permutări ale lui [n] \ {
}. La fiecare dintre schimbările lui ,primul ciclu while necesită n comparări,
efectuându-se astfel (n 1 comparări. Când se transformă din i în i + 1, atunci (
) se termină cu secvenţa i + 1, i 1, ..., 1, ceea ce face ca al doilea ciclu while să necesite i
comparări; se efectuează astfel comparări. Se obţine formula de recurenţă

unde în ultima relaţie se ţine seama de faptul că în final, pentru a obţine i = 0, se mai
efectuează n 1 comparări.

Fie = +

Înlocuind în (22) se obţine

(25)

Se arată uşor că din (25) se obţine

D = k! = k!

Rezultă că în expresia lui coeficientul lui n! este

= e 1

şi deci n! = 3,077 n!

Metoda descrisă mai sus este cea “naturală”, deşi nu cea mai eficientă.

26
Metoda 2. Metoda de generare a permutărilor se bazează pe reprezentarea
permutărilor prin vectorii de inversiune.

Fiind dată o permutare p de grad n, îi ataşăm un vector de inversiune i având tot n


componente astfel : pentru fiecare k [n], reprezintă numărul elementelor cu
proprietaţile > şi j < k, adică numărul componentelor p situate înaintea lui şi mai
mari decât el.

Exemplu. Permutării p = (3, 2, 1, 6, 5, 4) îi corespunde vectorului i = (0, 1, 2, 0, 1, 2).

Se observă că pentru orice m [n], < m. În particular = 0.

Trecerea de la p la i determină o funcţie : → unde este grupul permutărilor


de grad n , iar = {( , ..., )| 0 < k, }.

Această corespondenţă este biunivocă. Datorită faptului că | | = | | = n! este


suficient ca să fie injectivă, proprietate care se demonstrează prin inducţie. Pentru n = 1
afirmaţia este evident adevărată. Presupunem că este injectivă şi considerăm două
permutări p, p’ cu (p) = i = i’ = (p’). În mod evident sunt verificate
egalităţile =n+1 =n+1 = . Rezultă că = ( , ..., ) şi =(
, ..., ) sunt două permutări ale mulţimii [n + 1] { } cu ( ). Conform ipotezei de
inducţie rezultă = , deci p = p’.

Se observă că pentru k = 1, 2, ..., n 1, elementul este numărul natural cu


proprietatea că există exact numere mai mari decât el şi egale cel mult cu n, necuprinse în
{ }. Folosind această observaţie, algoritmul PERINV realizează trecerea de la un
vector de inversiune i la permutarea p = (i). Este utilizat un vector VIZ cu n elemente
iniţializate cu 0; în continuare determinarea unui este însoţită de atribuirea VIZ( )←1,
ceea ce permite ţinerea unei evidenţe a numerelor nealese încă drept componente ale lui p.

procedure PERINV(i, p, n)

integer i(n), p(n), VIZ(n)

for j = 1, n

VIZ(j)←0

27
repeat

for k = n, 1, 1

j←n

for m = 1,

while VIZ(j) = 1

j←j 1

repeat

j←j 1

repeat

while VIZ(j) ) = 1

j←j 1

repeat

←j; VIZ(j)←1

repeat

return

end

Pe baza celor de mai sus, generarea permutărilor de grad n poate fi făcută astfel : se
generează pe rând vectorii i ... cu = {0, 1, ..., k } şi din care fiecare
vector i se deduce permutarea p cu ajutorul procedurii PERINV. Dezavantajul constă în faptul
că timpul cerut de această procedură este de ordinul O( ).

Următoarele cinci metode folosesc reprezentarea permutărilor pe arbori.

Metoda 3. Pentru a descrie modul de lucru al algoritmului se construieşte un arbore


astfel:

- pe nivelul 1 apare rădăcina, etichetată cu permutarea identică

- dacă pe nivelul k apare permutarea , ..., , descendenţii ei de pe nivelul k + 1 vor fi


cele k + 1 permutări obţinute din p permutând circular ultimele k + 1 elemente.

Exemplu. Pentru n = 4, arborele corespunzător este prezentat parţial în figura I.5.

28
1234 1

1234 1234 2

1234 1342 1432 1243 1432 1324 3

1234 2341 3412 4123 3142 1243 4

Fig. I.5

în care pe nivelul 4 nu au fost figurate toate vârfurile.

Arătăm prin inducţie că pe nivelul k [n] apar cele k! permutări ale lui n k + 1, ...,
n precedate fiecare de elementele 1, 2, ..., n k.

Pentru k = 1, concluzia este evidentă. Să presupunem proprietatea de mai sus


adevărată pentru nivelul k + 1. Pe nivelul k + 1 apar (k + 1)! permutări, toate având aceleaşi
prime n k 1 elemente: 1, 2, ..., n k 1. Mai trebuie arătat că ele sunt distincte. Să
presupunem că există pe nivelul k + 1 două permutări identice. Evident ele nu pot avea
acelaşi tată. Deci suntem în situaţia din figura I.6.

p p’

k+1

q q

Fig. I.6

cu p = (1, ..., n k, , ..., ), p’ = (1, ..., n k, , ..., ),


q = (1, ..., n k 1, , ..., ). Deci q s-a obţinut din p, respectiv p’ permutând
circular ultimele k + 1 elemente de , respectiv ori. Cum în acest mod n k apare pe
aceeaşi poziţie rezultă că = ; aplicând lui q transformarea inversă obţinem că p = p’.
Contradicţie.

În particular pe nivelul n apar cele n! permutări din .

Algoritmul constă în parcurgerea vârfurilor terminale ale arborelui. Arborele nu va fi


construit explicit.

29
Se pleacă de la permutarea identică. Să presupunem că am ajuns la o permutare p de
pe ultimul nivel. Pentru a obţine permutarea următoare, facem o permutare circulară a tuturor
celor n elemente. Dacă permutarea p’ obţinută are ≠ 1, atunci a fost obţinută o permutare
nouă. Dacă = 1, atunci s-au terminat de parcurs descendenţii unui vârf de pe nivelul n 1.
„Urcăm” în arbore şi facem o permutare p’’. Dacă ≠ 2 atunci p’’ este permutarea
căutată. Dacă = 2 , atunci s-au terminat de parcurs descendenţii unui vârf de pe nivelul n
2 ; “urcăm” pe nivelul superior în arbore etc. În figura I.5 este desenată punctat o astfel de
trecere de la o permutare de pe ultimul nivel la alta. Dacă s-a efectuat şi o permutare a
ultimelor 2 elemente şi s-a ajuns la o permutare q cu = n 1, atunci ne oprim.

Se obţine astfel procedura PERM3, în care procedura CIRCU permută circular


ultimele k elemente ale lui p.

procedure PERM3(p, n, IG)

integer p(n)

if IG = 0 then for i = 1, n

p(i)← i

repeat

IG← 1; return

endif

for k = n, 2, −1

call CIRCU(p, n, k)

if ≠ n – k + 1 then return

endif

repeat

IG← 0; return

end

Metoda 4. Metoda 4 prezintă dezavantajul ca la fiecare trecere de la o permutare la


următoarea se efectuează printre altele o permutare circulară a tuturor elementelor. Metoda 4
înlătură acest dezavantaj prin construirea următorului arbore:

30
- pe nivelul 1 apare drept rădăcină permutarea identică

- dacă pe nivelul i ∈ {1, ..., n − 1} apare o permutare p, ea are n – i + 1 descendenţi şi


anume cei obţinuţi din p permutând circular ultimele n − i + 1 componente.

În figura I.7 este prezentat arborele construit ca mai sus pentru n = 4.

1234 1

1234 2341 3412 4123 2

1234 1342 1432 3412 3

1234 1243 1342 1324 1423 1432 _ _ _ _ _ 3412 3421 _ _ _ _ _ 4

Fig. I.7

Este evident că pe fiecare nivel i ≥ 2 apar n(n − 1)...( n − i + 2) vârfuri. Vom


demonstra că ele reprezintă permutări distincte, de unde va rezulta că pe nivelul n apar toate
cele n! permutări din grupul . Demonstraţie se face prin inducţie după i. Pentru i = 1,
afirmaţia este evident adevărată. Să presupunem că permutările de pe fiecare dintre primele i
nivele sunt distincte şi să presupunem că pe nivelul i + 1 apar două permutări p şi p’ egale.
Evident ele nu pot fi descendenţii direcţi ai aceluiaşi vârf. Se pune în evidenţă pe drumurile
care le unesc cu rădăcina vârful comun situat pe nivelul maxim k ; notând cu σ şi σ’
descendenţii săi în cele două drumuri, se obţine situaţia din figura I.8.

σ σ’ k+1

p p i+1

Fig. I.8

Din modul de construcţie al arborelui rezultă că ≠ . Atunci = ≠ = .


Contradicţie.

Se observă că dacă pentru fiecare vărf de pe intervalul i etichetăm în ordine cu


1, 2, ..., n − i + 1 arcele ce îl unesc cu descendenţii săi, atunci orice vârf de pe nivelul n este
determinat de etichetele arcelor de pe drumul de la rădăcină la vârful considerat. Se obţine o
bijecţie intre şi mulţimea [n] × [n − 1] × ... ×[2]. Aceste etichete vor fi memorate într-
un vector E.

31
Pentru parcurgerea vârfurilor terminale, se pleacă de la permutarea identică. Fie p o
permutare oarecare şi E vectorul asociat descris mai sus. Este evident că pentru a determina
permutarea p’ care urmează lui p se poate proceda astfel : se permută pe rând ultimele 2, 3, ...
componentele ( actualizând corespunzător vectorul E ) până când în urma permutării
ultimelor i componente şi a actualizării lui E(i), valoarea acestuia este cel mult n + 1 – i.
Dacă nu există un astfel de i, generarea s-a încheiat.

Procedura asociată metodei descrise este procedura PERM4 în care procedura CIRCU
permută circular ultimele k elemente ale lui p.

procedure PERM4(p, n, IG)

integer p(n), E(n)

if IG = 0 then for i = 1, n:

p(i)← i; E(i)← 1

repeat

IG ← 1; return

endif

for k = 2, n:

call CIRCU(p, n, k)

m← n + 1 – k ; E(m)← E(m) + 1

if E(m) ≤ k then return

else E(m)← 1

endif

repeat

IG ← 0; return

end

Metoda 5. Aceasă metodă se bazează pe modul recursiv de definire a permutărilor şi


anume : se obţine din generând pentru fiecare p = ( , ..., ) ∈ următoarele k
+ 1 permutări din :

| ( , ..., , k + 1), ( , ...,k + 1, ), ..., ( , k + 1,..., ), (k + 1, , ..., ) (26)

32
Ca urmare, permutările din sunt vârfurile terminale ale unui arbore construit
astfel :
- rădăcina este etichetată cu 1
- descendenţii unei permutări p = ( , ..., ) situate pe nivelul k sunt cele k + 1
permutări (26) unde k = 1, 2, ..., n – 1.
Arborelui îi putem ataşa un arbore în care toate vârfurile sunt permutări de
grad n astfel : pentru fiecare nivel k, permutările de pe acest nivel sunt completate cu k +
1, ..., n.
Este evident că pe fiecare nivel k din apar toate cele k! permutări de grad k.
Exemplu. Pentru n = 3, arborii şi apar în figurile I.9 a şi I.9 b.
1 123

12 21 123 213

123 132 312 213 231 321 123 132 312 213 231 321
a b
Fig. I.9

Parcurgerea vârfurilor terminale ale arborelui ( ) se face plecând de la


permutarea identică. Fie acum p o permutare oarecare. Dacă n apare pe o poziţie m > 1,
atunci se efectuează interschimbarea ↔ şi s-a obţinut noua permutare. Dacă = n,
atunci se permută circular cele n elemente, obţinându-se tatăl permutării p. În continuare,
dacă n − 1 apare pe o poziţie m ≠ 1, atunci se efectuează interschimbarea ↔ şi s-a
obţinut noua permutare ; în caz contrar se permută circular ultimele n − 1 poziţii şi se
încearcă deplasarea spre stanga a lui n − 2 etc.
Algoritmul corespunzător este prezentat în procedura PERM5.

procedure PERM5(p, n, IG)

integer p(n)

if IG = 0 then for i = 1, n

p(i) ← i

repeat

IG ← 1; return

endif

for i = n, 2, −1

33
m←1

while p(m) ≠ i

m←m+1

repeat

if m ≠ 1 then p(m − 1)↔p(m) ; return

endif

call CIRCP(p, n, i) /* se permută circular primele i componente ale lui p */

repeat

IG ← 0 ; return
end

Metoda 6. Această metodă este înrudită cu cea precedentă şi diferă doar prin aceea că
cele k +1 permutări din obţinute dintr-o aceeaşi permutare p a lui sunt următoarele :

( , ..., , i) unde i = k + 1, ..., 1 , iar = (27)

Exemplu. Pentru n = 3, arborii şi apar în figura I.10.


1 123

12 21 123 213

123 132 231 213 312 321 123 132 231 213 312 321
a b
Fig. I.10
Observaţie. Trecerea de la o valoare i la următoarea în (27) presupune doar
micşorarea ultimei componente cu o unitate şi marirea cu 1 a acelei componente care era
egală cu i − 1.
Se pleacă de la o permutare identică. Dacă = 1, se trece la tatăl permutării curente
micşorând cu o unitate primele n − 1 componente şi punând ← n ; apoi se reia
raţionamentul înlocuind pe n cu n − 1.

34
procedure PERM6(p, n, IG)

integer p(n)

if IG = 0 then for i = 1, n

p(i) ← 1

repeat

IG ← 1; return

endif

for i = n, 2, −1

if p(i )≠ 1 then p(i ) ← p(i ) − 1; j ← 1

while p(i ) ≠ p(i )

j←j+1

repeat

p(i ) ← p(i ) + 1; return

endif

for j = 1, i − 1

p(i ) ← p(i ) − 1

repeat

p(i ) ← i

repeat

IG ← 0; return

end

Metoda 7. Metoda, mai eficientă, nu este de fapt o metodă nouă. Ea urmează aceeaşi
idee ca metoda 5, diferenţa constând în faptul că în arborele ataşat se modifică ordinea în care
apar descendenţii anumitor vârfuri, ceea ce permite eliminarea permutărilor circulare,
înlocuindu-le prin deplasări ale unei anumite componente , adică prin efectuarea unei
interschimbări ↔ ( dacă se deplasează spre dreapta ) sau ↔ ( dacă
se deplasează spre stânga ). În acest scop se introduce un vector d cu n componente în care

35
are valoarea − 1 sau valoarea 1 după cum urmează să se deplaseze spre stânga sau
dreapta.

De asemenea se elimină operaţiile de căutare ale unui element k într-o permutare p


prin introducerea unui vector i cu n componente, memorând inversa permutării p : atunci este
clar că valoarea k se află în p pe poziţia adică =k.

Observaţie. Ideile prezentate mai sus pot fi aplicate şi celorlalte metode descrise
anterior.
Pentru a descrie arborele ataşat metodei, pe fiecare nivel k vom numerota
permutările de pe acest nivel în A−preordine cu 1, 2, ..., k !. Arborele se construieşte astfel :
- rădăcina este permutarea identică;
- dacă ( , ..., ) este permutarea cu numărul de ordine j de pe nivelul k , atunci
descendenţii săi sunt în ordine:
- - ( , ..., , k + 1), ( , ..., k + 1, ), ..., (k + 1, , ..., )

dacă j este impar sau


- - (k + 1, , ..., ), ( , k + 1, ..., ), ..., ( , ..., , k + 1)

dacă j este par.

Pentru cazul particular n = 5, arborele ataşat metodei este prezentat în figura IV.11 dar
înlocuindu-se sensul stânga→dreapta cu sensul sus→jos, adică s-a considerat simetricul sau
faţă de diagonala stânga sus→dreapta jos a hârtiei. În dreptul permutărilor de pe fiecare nivel
este notată şi modalitatea în care se determină succesorul lor. De asemenea sunt puse în
evidenţă schimbările sensurilor de parcurgere a elementelor.

1234 ← 4
1243 ← 4
123 1423 ← 4
4123 ← 3 ( 4 îşi schimbă sensul )
12 4132 4→
132 1432 4→
1342 4→
1324 ← 3 ( 4 îşi schimbă sensul )

36
3124 ← 4
312 3142 ← 4
1 3412 ← 4
4312 ← 2 ( 4, apoi 3 îşi schimbă sensul )
4321 4 →
3421 4 →
321 3241 4 →
3214 3 → ( 4 îşi schimbă sensul )
21 2314 ← 4
231 2341 ← 4
2431 ← 4
4231 3 → ( 4 îşi schimbă sensul )
4213 ← 4
213 2413 ← 4
2143 ← 4
2134

Fig. I.11

Pe baza arborelui ataşat, se poate face acum o descriere a metodei. Se pleacă de la


permutarea iniţială şi se stabilesc sensurile de deplasare a elementelor ca fiind îndreptate
către stânga. Fie p = ( , ..., ) permutarea al cărui succesor p ’ trebuie determinat. Se
încearcă deplasarea lui n. Dacă aceasta este posibilă, adică dacă + ∈ {1, 2, ..., n },
atunci se efectuează interschimbarea ↔ obţinându-se permutarea p ‘ căutată. În caz
contrar se schimbă sensul de deplasare al lui n şi se încearcă deplasarea lui n − 1. Dacă
aceasta este posibilă, adică dacă + ∈ { 1, ..., n } şi < n − 1, atunci se
efectuează interschimbarea ↔ obţinându-se permutarea p ’ căutată. În caz
contrar de schimbă sensul de deplasare al lui n − 1 şi se încearcă deplasarea lui n − 2 etc.

Se remarcă faptul că un element k nu poate fi deplasat pe o poziţie conţinând o


valoare mai mare decât k . Procesul de generare se opreşte în momentul în care se ajunge în
situaţia de a-l deplasa pe 1.

Metoda descrisă este concretizată în procedura PERM7.

procedure PERM7(p, n, IG, i, d )

integer p(n ), i(n ), d(n )

if IG = 0 then for j = 1, n :

←j , ←j ; ← −1

37
repeat

IG ← 1; return

endif

for j = n, 2, −1

m← +

if m ≤ n ⋀ m ≠ 0 then if < j then ← ; ←i

←j; ←m

return

endif

endif

←−

repeat

IG ← 0

return

end

Este de remarcat faptul că se poate renunţa la verificarea condiţiei m ≤ n ⋀ m ≠ 0


dacă extindem vectorul p cu două componente şi , ambele având valoarea n + 1.
Există multe limbaje de programare ( PASCAL etc.) care permit ca indicele cel mai mic
pentru componentele unui vector să fie 0. În cadrul limbajului algoritmic folosit aici, acest
lucru nu este posibil, dar poate fi folosit cu translatarea elementelor lui p cu o unitate.

Este evident că atribuirile care modifică lui p şi i se efectuează pentru fiecare vârf
terminal al arborelui cu excepţia celui iniţial; deci sunt necesare 4(n ! − 1) astfel de atribuiri.
De asemenea se arată uşor prin inducţie că numărul comparărilor < 1 este egal cu numărul
vârfurilor arborelui, adică . Obţinem succesiv :

= n ! + (n − 1)! ≤ n ! +

(n − 1)! = n ! ≈ n !
(27)

38
Corectitudinea metodei rezultă din corectitudinea metodei 5, deoarece în ambele
metode pe fiecare nivel în arborii ataşaţi apar aceleaşi permutări, dar în alta ordine.

I.6. Generarea aranjamentelor

Vom descrie algoritmi de generare a tuturor grupărilor de m elemente distincte din


mulţimea [n], două grupări diferind fie prin natura, fie prin ordinea elementelor. Se ştie că
există asemenea grupări. În cele două metode care vor fi prezentate, se presupune că
0 < m ≤ n.
Metoda 1. Această primă metodă constă în generarea tuturor m-combinărilor de n
elemente, pentru fiecare astfel de m-combinare generându-se toate cele m ! permutări ale sale.
Datorită faptului că nu s-a presupus niciunde că variabilele locale ale unei proceduri
(cele ce nu apar în lista de parametri) nu îşi modifică valoarea între două apelări succesive ale
procedurii, pe lângă vectorul a cu m componente memorând aranjamentul curent se vor folosi
şi vectorii c şi p tot cu m componente conţinând m-combinarea, respectiv permutarea curentă.
Pentru vectorii a şi c se poate folosi acelaşi indicator de generare IG, dar pentru vectorul p
trebuie folosit un indicator de generare IG1 distinct.
Se obţine astfel procedura ARANJ1.

procedure ARANJ1 ( a, n, m, IG, c, p, IG1)

integer a(m), c(m), p(m)

if IG = 0 then for i = 1, m

← i; ← i; ←i

repeat

IG ← 1; IG1 ← 1; return

endif

call PERM(p, m, IG1)

if IG1 ≠ 0 then for i = 1, m

repeat

else call COMB(c, n, m, IG)

39
if IG = 1 then for i = 1, m

←i; ←

repeat

endif

endif

return

end

Metoda 2. Această metodă va genera aranjamente în ordine lexicografică, adică


folosind metoda backtracking. Se pleacă de la a = (1, 2, ..., m). Fie a = ( , ..., ) un
aranjament oarecare. Pentru determinarea succesorului său, se va determina mai întâi cel mai
mare indice i cu proprietatea că poate fi mărit. Un element poate fi mărit dacă toate
valorile + 1, ..., n cu care ar putea fi înlocuit nu sunt disponibile ; pentru a efectua uşor
aceste verificări este utilă introducerea unui vector DISP cu n elemente, unde DISP(i) este 0
sau 1 după cum valoarea i este sau nu disponibilă, adică apare sau nu în vectorul a curent.

Se observă că în procesul căutării ( în ordine descrescătoare ) a indicelui i cu


proprietatea menţionată, ori de câte ori se ajunge la un element, valoarea sa trebuie făcută
disponibilă (indiferent dacă este vorba de indicele i căutat sau de un indice mai mare decât
el).

În momentul în care a fost determinat indicele i, elementele , , ..., vor primi


ca valori cele mai mici numere disponibile, bineînteles în ordine crescătoare, deoarece
vectorul a’ căutat este cel mai mic vector cu elemente distincte mai mare decât a în ordine
lexicografică. Dacă nu există un indice i cu proprietatea menţionată, înseamnă că s-a ajuns la
vectorul ( n − m + 1, n − m + 2, ..., n), deci procesul generării s-a încheiat. Se obţine astfel
procedura ARANJ2.

procedure ARANJ2(a, n, m, IG, DISP)

integer a(m), DISP(n)

if IG = 0 then for i = 1, m

←i; ←1

repeat

40
for i = m + 1, n

←0

repeat

IG ← 1; return

endif

for i = m, 1, −1

←0

for j = + 1, n

if = 0 then /* se contruiesc noile valori ,..., */

←j; ← 1; k ← 0

for l = i + 1, m

do

k←k+1

until =0

←k; ←1

repeat

return

endif

repeat

repeat

IG ← 0 ; return

end

I.7. Generarea combinărilor cu repetiţie

41
Se numeşte m-combinare cu repetiţie sau m-selecţie a n elemente un vector a ∈ [n
satisfăcând relaţiile:

≤ ≤ ... ≤
(28)

În cazul particular când toate inegalităţile din relaţia (28) sunt stricte (ceea ce
implică m ≤ n ) se obţine definiţia m-combinărilor. Sunt prezentate trei metode de
generare a m-combinărilor cu repetiţie.

Metoda 1. Generează în ordine lexicografică şirurile nedescrătoare cu m elemente din


[n]. Se pleacă de la vectorul a = (1, 1, ..., 1). Fiind dat un vector oarecare a satisfăcând (28),
determinarea succesorului său se face determinând mai întâi cel mai mare indice i cu <n
( dacă un astfel de indice nu există, înseamnă că generarea s-a terminat); atunci succesorul lui
a se obţine din aceasta înscriind pe poziţiile , ..., valoarea + 1. Procedura
corespunzătoare este procedura COMBREP1.

procedure COMBREP1(a, n, m, IG)

integer a(m)

if IG = 0 then for i = 1, m :

←1

repeat

IG ← 1 ; return

endif

for i = m, 1, −1

if ≠ n then x ← +1

for j = i, mi

←x

repeat

42
return

endif

repeat

IG ← 0 ; return

end

Metoda 2. Pentru memorarea submulţimii { , ..., } se foloseşte reprezentarea


(ii) (subcap 1). O mică modificare a acestei reprezentări permite şi înglobarea factorilor de
repetiţie. Mai precis se utilizează un vector r cu n componente naturale cu semnificaţia că
pentru orice i, reprezintă numărul de repetări ale lui i în m-combinarea cu repetiţie
respectivă. Bineînţeles că = m iar < < ... < (29).

Pentru a obţine m-combinarile cu repetiţie în aceeaşi ordine ca în metoda precedentă,


vectorii r trebuie generaţi în ordine lexicografică descrescătoare. Se pleacă de la vectorul r =
(m, 0, ..., 0). Fie r vectorul curent al cărui succesor r’ trebuie determinat ; r are forma :

r = ( , ..., , 0, ..., 0, , 0, ..., 0) (30)

unde ≠ 0, ≠ 0 sunt ultimele elemente nenule ale vectorului ; indicele i poate lua şi
valoarea 0 şi anume atunci când = m. Atunci în succesorul r’ al lui r componentele care îşi
modifică valoarea sunt următoarele :

1) dacă j ≠ n şi > 1, atunci = −1; = 1. În plus (i, j) ← (j,j + 1)

2) dacă j ≠ n şi = 1 atunci =0; = 1. În plus j ← j + 1

3) dacă j = n şi i = 0 (echivalent cu = m), atunci generarea s-a încheiat

4) dacă j = n şi i ≠ 0, atunci = −1; = + 1. În plus dacă i < n − 1, punem


= 0.

Se observă că trecerea de la un vector r la succesorul său necesită determinarea


prealabilă a indicilor i şi j ; mai mult, memorarea de la un pas la altul a valorilor i şi j nu evită
efectuarea de căutări pentru actualizarea lor.

43
Metoda 3. Această metodă utilizează pentru memorarea mulţimii { , ..., }
reprezentarea (i) (subcap 1), adică un vector a cu m componente care în primele sale k
componente conţine elementele , ..., satisfăcând (29). Valorile , ..., sunt memorate
în ordine într-un vector r.

Faptul că se foloseşte acelaşi algoritm ca în metoda 2, adaptat numai la noua


reprezentare, permite scrierea directă a procedurii COMBREP3 corespunzătoare.

procedure COMBREP3 ( a, n, m, r, k, IG)

integer a(m), r(m)

if IG = 0 then IG ← 1; k ← 1; ← 1; ← m; return

endif

if ≠ n then if > 1 then = − 1; = +1

k ← k + 1; ←1

else = +1

endif

return

endif

if > 1 then ← − 1; ← + 1; ← +1

else k ← k − 1; ← + 1; ← +1

endif

return

end

Se observă că în metoda 3 se foloseşte un vector în plus faţă de metda 2, ceea ce


permite însă determinarea succesorului unui vector r în timp constant.

I.8. Generarea partiţiilor unui număr natural

44
Problema generală ce va fi tratată este cea a determinării tuturor modalităţilor de
scriere a unui număr n sub forma

n= + + ... + (31)

unde numerele naturale nenule , ..., se numesc părţi ale lui n. Din această problemă
generală se desprind mai mult probleme ce se deosebesc între ele prin restricţii asupra
părţilor.

I. Problema compunerii. În cadrul acestei probleme se cere > 0, ∀i; în plus ordinea
elementelor în scrierea părţilor lui n prezintă importanţă.

Se observă că fiecare compunere n = + + ... + este bine determinată de


alegerea pe segmentul [0, n] a punctelor de coordonate întregi , + , ..., + ... + .
Există deci o corespondenţă biunivocă între mulţimea compunerilor lui n şi mulţimea
submulţimilor lui {1, 2, ..., n − 1}. Ca urmare, compunerile lui n sunt în număr de şi
ele pot fi generate uşor generând submulţimile lui {1, 2, ..., n − 1}; dacă{ , ..., } este o
astfel de submulţime cu < < ... < , atunci se deduce uşor că :

= ; = − ; ... ; = − ; =n−

Compunerile lui n din exact k părţi sunt bine determinate de alegerea a k − 1 valori
distincte din mulţimea {1, … , n − 1}. Drept urmare există astfel de compuneri care se
deduc la fel ca mai sus din cele (k − 1)-combinări de n − 1 elemente.

II. Problema descompunerii. În această problemă se cere ≥ 0, ∀i; ordinea


elementelor nu reprezintă importanţă. Ca urmare, se va presupune fie că ≤ ≤ ... ≤ ,
fie că ≥ ≥ ... ≥ .

O primă modalitate de rezolvare a problemei pleacă de la reprezentarea oricărei


descompuneri n = + + ... + sub forma unui vector a cu n elemente ale cărui ultime
n − k componente având valoarea 0. Vectorii vor fi generaţi în ordine lexicografică. Primul
vector va fi deci (0, 0, ... , 0, n) iar ultimul va fi (1, 1, ... , 1). Fie a = ( , , ... , ) un
vector cu ≤ ≤ ... ≤ . Pentru a determina vectorul a’ care îi succede în ordine
lexicografică, se determina mai întâi cel mai mare indice i cu proprietatea + 2 ≤ .
Atunci a’ are forma:

a’ = ( , ... , , + 1, ... , + 1, )

45
cu =n− . Dacă nu există vreun I cu proprietatea menţionată, rezultă că suntem
în situaţia a = (1, 1, ... , 1), deci nu mai există o nouă descompunere. Algoritmul
corespunzător metodei descrise apare în procedura DESCOMP1.

procedure DESCOMP1( a, n, IG)

integer a(n)

if IG = 0 then for i = 1, n − 1

←0

repeat

← n; IG ← 1; return

endif

s←

for i = n − 1, 1, − 1:

if +2≤ then m ← +1

for j = i, n − 1

←m

repeat

← s − (n − i − 1)m − 1; return

else s ← s +

46
endif

repeat

IG ← 0; return

end

Observaţie. Dacă se dă k ≤ n şi se cer descompunerile lui n în exact k părţi, atunci


problema poate fi rezolvată făcând în procedura DESCOMP1 următoarele modificări :

- vectorul a are k componente ; iniţial a ← (1, … , 1, n − k + 1)

- căutarea lui i începe cu valoarea k − 1.

O a doua modalitate de rezovare a problemei descompunerii pleacă de la formularea


unei descompuneri ca fiind o combinare cu repetiţie (selecţie) pentru care suma elementelor
este egală cu n.

Vom considera mai întâi reprezentarea unei selecţii de sumă n ca fiind un vector r cu
n componente aparţinând mulţimii {0, 1, …, n} vector care are proprietatea:

=n (32)

Primul şi ultimul vector generat vor fi deci vectorii (n, 0, ..., 0) respectiv (0, ..., 0, 1).
Fie r un vector satisfăcând (32), vector pentru care se caută succesorul său r’ în ordine
lexicografică inversă. Fie i cel mai mic indice cu >0. Conform condiţiei (32), niciuna dintre
primele i componente nu poate fi mărită cu o unitate, deci trebuie mărită o componentă de pe
celelalte poziţii. Deosebim următoarele situaţii:

- dacă > 1, vectorul r’ va avea forma următoare:

( , 0, …, 0, , + 1, , …, )

cu = * i − (i + 1); în plus dacă i > 1 se pune = 0.

- dacă = 1, se caută cel mai mic indice j > i cu > 0 (se observă că un astfel de
indice j nu există doar dacă i = n , deci dacă s-a încheiat generarea). Atunci vectorul
r’ are forma următoare:

( , 0, …, 0, = 0, 0, …, 0, = 0, + 1, , …, )

cu = i + *j − (j + 1).

47
Metoda descrisă mai sus se poate adopta uşor situaţiei în care pentru reprezentarea
unei selecţii se utilizează un vector p care în primele sale k poziţii conţine părţile distincte ale
descompunerii precum şi un vector r care în primele sale k poziţii conţine factorii de repetiţie
pentru părţile , …, . Se observă că este avantajoasă memorarea părţilor , …, în
ordine descrescătoare, deoarece modificările se efectuează asupra părţilor cele mai mici. Se
obţine procedura DESCOMP2.

procedure DESCOMP2(n, p, r, k, IG)

integer p(n), r(n)

if IG = 0 then k ← 1; ← 1; ←n

IG ← 1; return

endif

if IG = 0 then IG ← 0; return

endif

s← *

if = 1 then k ← k − 1; s ← s + *

endif

if = + 1 then k ← k − 1 /* se verifică dacă valoarea + 1 apare în p */

← +1

else + 1; ←1

endif

if s > then k ← k + 1; ← 1; ←s−

endif

return

end

Se observă uşor că procedura DESCOMP2 necesită un timp constant pentru


trecerea de la un vector r la succesorul său.

48
Fie p(n, k) numărul descompunerilor lui n în k părţi. Propoziţia care urmează permite
determinarea recursivă a acestor numere.

Propoziţie. Numerele p(n, k) verifică următoarele relaţii:

- p(n, 1) = p(n, n) = 1; p(n, k) = 0 pentru n < k (33)

- p(n, 1) + p(n, 2) + ... + p(n, k) = p(n + k, k) (34)

Relaţiile (33) sunt evidente. Pentru a demontra relaţia (34), notăm prin �(n, k)
mulţimea descompunerilor lui n în k părţi, iar prin �(n, k) mulţimea descompunerilor lui n în
cel mult k părţi. Atunci sunt îndeplinite relaţiile:

�(n, k) = ; | �(n, k) | = p(n,1) + p(n,2) + ... + p(n,k) (35)

Fie φ: �(n, k) → ) aplicaţia care duce fiecare descompunere n = + +


... + cu ≥ ≥ ... ≥ > 0 în următoarea descompunere a lui n + k:

n+k=( + 1) + ... + ( + 1) + 1 + ... +1 (36)

unde secvenţa finală de valori egale cu 1 are lungimea k − i. Aplicaţia φ este evident
injectivă. Ea este şi surjectivă. Într-adevăr fie n + k = + + ... + o descompunere a lui
n + k în k părţi unde ≥ ≥ ... ≥ ≥ 1. Fie i cel mai mare indice cu > 1. Evident
i≤k. Atunci descompunerea n = ( − 1) + ... + ( − 1) este din �(n, k), iar imaginea sa
prin φ este tocmai descompunerea (36). În conseciinţă φ este bijectivă. Rezultă | �(n, k) | =
=| ) | ceea ce ,ţinând cont de (35), conduce la relaţia (34).

III. Problema submulţimilor de sumă dată. Această problemă constă în următoarele:


se dau un număr real M > 0 şi o mulţime A = { , ... , } de numere pozitive. Se cer toate
submulţimile B ale lui A cu proprietatea = M.

Pentru submulţimile B ale lui A se va folosi reprezentarea cu ajutorul vectorului


caracteristic. În particular o soluţie este un vector x = ( , …, ) ∈ {0,1 cu =
M. Componentele vectorului x vor fi determinate succesiv conform strategiei genereale
backtracking.

49
Fie stabilite valori pentru , ..., . Există mai multe modalităţide a alege condiţiile
de continuare care să elimine unele alegeri ale lui . Cele mai naturale par următoarele:

Din modul de funcţionare al metodei backtracking rezultă că prima condiţie trebuie


verificată doar pentru = 0, iar a doua doar pentru = 1. Pentru a evita calculul repetat al
sumelor din (37) şi (38), vom păstra în variabilele r şi s valorile curente ale celor două sume:

s= ,r= (39)

Putem scrie procedura SUMASUB de rezolvare a problemei propuse.

procedure SUMASUB(A, n, M, k, IG, x)

array A(n), x(n)

if IG = 0 then s ← 0; r = ; k ← 1; ←−1, IG ← 1

endif

while k > 0

v←−1

while <1

→ + 1; call POSS(A, x, n, k, r, s, M, v)

if v ≠ 0 then exit

endif

50
repeat

case v = − 1 : s ← s − ; k ← k − 1; r ← r +

v = 0 : k ← k − 1; r ← r +

v=1:r←r− ; k ← k + 1; ←−1

v = 2 : write , ..., ; k ← k − 1; r ← r +

return

endcase

repeat

IG ← 0; return

end

În instrucţiunea case din această procedură, în situaţia v = − 1 se poate ajunge numai


dacă în ciclul while care o precede s-a intrat cu valoarea = 1. Procedura POSS verifică
dacă sunt îndeplinite conditiile de continuare; variabila v primeşte valoarea 0 (dacă nu sunt
îndeplinite condiţiile de continuare), 1 (dacă sunt îndeplinite condiţiile de continuare dar nu
s-a ajuns la o soluţie rezultat) sau 2 (dacă ( , …, ) este o soluţie rezultat).

procedure POSS(A, x, n, k, r, s, M, v)

array x(n), A(n)

if = 0 then if s + r − ≥ M then v ← 1

else v ← 0

endif

else case s + < M: v ← 1; s ← s +

s+ = M: v ← 2

s+ > M: v ← 0

endcase

endif

51
return

end

IV. Problema plaţii unei sume în bancnote de valoare dată. Fie S ∈ ℕ reprezentând
o sumă ce trebuie plătită. Fie , ..., valorile bancnotelor existente; se presupune că există
suficiente bancnote din fiecare valoare. Se cer modalităţi în care suma S poate fi plătită în
bancnotele existente, adică vectorii x ∈ satisfăcând relaţia:

S=

O variantă a problemei enunţate constă în a determina numărul minim de bancnote în


care poate fi plătită suma S.

Prin k va fi notat indicele curent în vector, având semnificaţia că , …, sunt


cunoscute, iar SC reprezintă suma curentă ce mai trebuie acoperită cu bancnotele de valori
, …, . Va fi folosită metoda backtracking, combinată cu metoda Greedy,
corespunzător faptului că:

> >…>

aceasta permiţând reducerea numărului de calcule şi determinarea mai rapidă a numărului


minim de bancnote cu care poate fi acoperită suma S; aceasta presupune bineînţeles
determinarea valorilor soluţie x în ordine lexicografică descrescătoare.

Cele de mai sus sunt materializate în procedura PLATAS.

procedure PLATAS(n, a, x, S, IG)

integer a(n), x(n)

if IG = 0 then for i = 2, n:

←0

repeat

IG ← 1; k ← 1; ← + 1;

SC ← S −

endif

SC ← SC + ;k←n−1

while k > 0

52
if > 0 then ← − 1; SC ← SC +

for j = k + 1, n:

← ; SC ← SC −

if SC = 0 then for m = j + 1, n

←0

repeat

return

endif

repeat

SC ← SC + ;k←n−1

else k ← k − 1

endif

repeat

IG ← 0; return

end

Observaţie. Din procedura PLATAS se poate deduce uşor procedura corespunzătoare


reprezentării unei soluţii prin doi vectori x şi i cu n componente naturale şi valoarea k astfel
încât = S cu > 0 şi <…< , reprezentarea care permite evitarea căutării
elementelor strict pozitive.

I.9. Relaţii binare. Închiderea tranzitivă

Fie A o mulţime finită. Vom presupune că A = {1, 2, …, n}. Fie R o relaţie binară pe
A, deci R ⊂ A × A.

Pentru reprezentarea relaţiei R, se observă că i se poate ataşa un graf orientat G = (X, Γ)


cu X = A şi Γ = {(i,j)|iRj}. Această corespondenţă este evident biunivocă. Drept urmare,
reprezentarea relaţiilor binare este analoagă reprezentării grafurilor orientate. De exemplu

53
reprezentarea grafurilor prin matricea adiacenţă induce reprezentarea relaţiilor prin matricea
adiacenţă M de ordin n în care

= (40)

reprezentarea ce constitue de fapt echivalentul matricial al vectorului caracteristic al unei


submulţimi.

Se va folosi reprezentarea prin matricea adiacentă pentru a determina închiderea


tranzitivă a unei relaţii R. Dată fiind o relaţie R pe mulţimea A, relaţia R* este definită astfel:
pentru orice i, j ∈ A, iR*j dacă şi numai dacă există elementele , ..., ∈ A cu i = , j =
şi k ≥ 1 astfel încât R , R , ..., R .

Un algoritm simplu de determinare a închiderii tranzitive este prezentat în procedura


TRANZ.

procedure TRANZ(M, n)

integer M(n,n)

for j = 1, n:

for i = 1, n

if = 1 then for k = 1, n

if = 1 then ←1

endif

repeat

endif

repeat

repeat

return

54
end

Pentru a demonstra valabilitatea algoritmului, se notează prin valoarea matricii


M după execuţia ciclului for exterior pentru j = 1, 2, ..., p; în plus, prin se notează
valoarea iniţială a matricii M. Arătăm că = M* unde M* este matricea ataşată relaţiei
R*. Aceasta revine la a demonstra că pentru orice i,k ∈ {1, …, n}, = 1 dacă şi numai
dacă = 1.

Demonstrăm mai întâi prin inducţie dupa p că oricare ar fi i,k ∈ {1, …, n} cu =

1, rezultă că există = i, , …, = k cu s ≥ 1 astfel încât = =…= .


Pentru p rezultatul este imediat. Presupunând proprietatea adevărată pentru 1, 2, ..., p, să
considerăm perechea (i, k) cu = 1. Dacă = 1, atunci proprietatea este verificată.

În caz contrar, conform algoritmului, există j ≤ p cu = = 1. Aplicănd ipoteza de


inducţie se obţine imediat rezultatul dorit. Proprietatea enunţată aplicată pentru p = n face ca
din = 1 să rezulte = 1.

Fie acum (i, k) cu = 1. Atunci există , ..., cu = i, = k şi s ≥ 1 astfel încât


= =…= = 1, adică =…= = 1. Fie = min { , ..., }.

Atunci din = = 1 şi = = 1, rezultă conform algoritmului că

= 1 şi deci = … = = ... = = 1. Aplicând repetat acest

raţionament se obţine că = = 1.

Observaţie. Transpunând lucrurile în limbajul teoriei grafurilor, dacă M este matricea


adiacentă a unui graf, atunci M* se numeşte matricea drumurilor, corespunzător faptului că
= 1 dacă şi numai dacă există un drum de la i la j.

Observaţie. În cazul particular când R este relaţie de echivalenţă, reprezentarea ei se


simplifică mult. Legătura între partiţiile unei mulţimi constă în faptul că orice relaţie de
echivalenţă pe A induce o partiţie a lui A, corespondenţă ce este biunivocă, după cum se
verifică uşor.

I.10. Generarea partiţiilor unei mulţimi finite

Fie A o mulţime finită. O partiţie a lui A este o descompunere a sa de forma:

55
A= ∪ ∪…∪ (41)

unde cele k submulţimi , …, (numite clase) sunt nevide şi două câte două disjuncte.

Exemplu {1, 2, 3, 4, 5, 6} = {5, 4} ∪ {2, 3} ∪ {6, 1}

Există multe posibilităţi de a reprezenta o partiţie, dintre care menţionez următoarele,


toate folosind un vector V cu n componente:

a) V conţine în ordine elementele claselor , …, , elementul cu care începe o nouă


clasă fiind trecut în V cu semn schimbat. Pentru a nu obţine aceeaşi partiţie de mai
multe ori, elementele fiecărei clase sunt ordonate crescător, iar clasele sunt ordonate
crescător după primul element (elementul având cea mai mică valoare) al fiecărei
clase. Pentru exemplul considerat se obţine:

{1, 2, 3, 4, 5, 6} = {1, 6}∪ {2, 3} ∪ {4, 5}

V = (− 1, 6, − 2, 3, − 4,5)

b) a doua modalitate de reprezentare este asemănatoare cu prima, deosebirea constând în


faptul că elementele claselor cu număr de ordine par sunt înscrise în V cu semn
schimbat. Pentru exemplul considerat se obţine vectorul V = (− 1, 6, − 2, − 3, 4, 5).

c) fiecare componentă V a vectorului V desemnează numărul clasei din care face parte
elementul a, clasele fiind ordonate în modul descris la reprezentarea a). Pentru
exemplul considerat V = (1, 2, 2, 3, 3, 1).

d) fiecare componentă V a vectorului conţine un reprezentant al clasei din care face parte
a (de obicei cel mai mic element al clasei).

Vom considera că A = [n].

Fie [n − 1] = ∪ ∪…∪ o partiţie a lui [n − 1]. Din această partiţie se obţin


k + 1 partiţii ale lui [n] şi anume

(42)

56
Aceasta sugerează metoda de generare a partiţiilor pe care o descriem în continuare.
Se pleacă de la partiţia . Apoi elementul n trece pe rând în clasele
precedente până ajunge în prima clasă. După aceea el va forma singur o clasă (revenindu-se
deci la o partiţie precedentă) şi se încearcă deplasarea lui n − 1 spre stânga, adică obţinerea
unei noi partiţii a lui [n − 1]; dacă aceasta reuşeşte, se reia procedeul (încercând deci să-l
deplasăm pe n la stânga), în caz contrar încercăndu-se deplasarea lui n − 2 spre stânga etc.
Procesul de generare se opreşte atunci când ajungem în situaţia de a-l deplasa pe 1 spre
stânga, ceea ce nu este posibil deoarece 1 apare totdeauna în prima clasă.

Din faptul că orice partiţie a lui [n] se obţine dintr-o partţie a lui [n − 1] în unul dintre
modurile care apar în (42), rezultă că metoda descrisă generează intr-adevăr toate partiţiile lui
[n].

Dacă se foloseşte pentru reprezentarea partiţiilor modalitatea d), metoda descrisă mai
sus este realizată de procedura PART.

procedure PART(V, n, IG)

integer V(n)

if IG = 0 then for i = 1, n

V(i) ← i

return

IG ← 1; return

endif

k←n

do

if V(k) ≠ 1 then j ← 1 /* se caută clasa precedentă celei în care apare k */

for i = 2, k − 1

if V(i) > j ∧ V(i) < V(k) then j ← V(i)

endif

57
repeat

V(k) ← j /* k este trecut în clasa precedentă */

return

else V(k) ← k; k ← k − 1

endif

until k = 1

IG ← 0

return

end

În algoritmul PART, la căutarea clasei precedente celei în care apare k, s-a ţinut cont
de faptul că reprezentantul ei este mai mic decât k, precum şi faptul că V(1) = 1.

Observaţie. Dacă se notează prin S(n, k) numărul partiţiilor lui [n] în k clase, atunci
din (42) se deduce formula de recurenţă.

S(n, k) = kS(n − 1, k) + S(n − 1, k − 1) (43)

care împreună cu relaţiile

(44)

permite determinarea valorii S(n, k) pentru orice pereche de numere naturale (n, k).

Numerele {S(n, k)} se numesc numerele lui Stirling de speţa a doua.

PREZENTAREA APLICAŢIEI
1. Reprezentarea mulţimilor şi generarea iterativă a elementelor

58
1.1 Noţiuni Teoretice

Fie A = { ,...., } o mulţime oarecare cu n elemente. Pentru reprezentarea ei se


foloseşte de obicei un vector cu n componente în care se introduc elementele mulţimii. Este
important de notat că o astfel de asociere mulţime → vector stabileşte implicit o ordine a
elementelor mulţimii, corespunzătoare ordinii în care apar elementele în vector.

Fie B o submulţime a lui A. Există mai multe modalitaţi de reprezentare a


submulţimilor, cele mai folosite fiind următoarele:

(i) - printr-un vector cu n componente, unde elementele submulţimii sunt plasate


la începutul vectorului, precizându-se în plus numărul lor sau introducând pe restul
poziţiilor din vector o valoare care nu aparţine mulţimii A = [n] = {1,2,…,n}.

(i’) - printr-un vector cu n componente, construit analog cu cel din reprezentarea


(i) cu deosebirea că elementele submulţimii sunt plasate la sfarşitul vectorului.

(ii) - prin vectorul caracteristic al submulţimii, adică acel vector c {0,1 definit
de:

c(i) = (1)

În aceasta lucrare vom presupune totdeauna că A = [n] = {1,...,n} deoarece între o


orice mulţime A={ ,...., } si [n] există o bijecţie, de exemplu cea dată de corespondenţa
.

Submulţimile care vor fi generate în această lucrare vor fi de urmatoarele două tipuri:

- submulţimi în care este importantă ordinea în care apar elementele.

- submulţimi în care nu conteaza ordinea în care apar elementele.

Pentru submulţimile de al doilea tip, dacă folosim pentru ele una dintre reprezentările
(i) sau (i’), vom conveni că ordinea în care apar elementele să fie cea crescătoare; în acest
mod vom evita generarea de mai multe ori a aceleaşi submulţimi.

Toate generările ce vor fi prezentate vor avea un caracter iterativ, fiecare element
fiind dedus din anteriorul său. Algoritmul general de construire a unui nou element apare în
procedura GEN. El foloseşte pe langă un vector V de dimensiune n ( în care vor fi generate
succesiv submulţimile ) şi un indicator de generare IG. La apelarea procedurii, IG are fie

59
valoarea 0 ( dacă este vorba de prima apelare, deci trebuie făcuta o iniţializare ), fie valoarea
1 ( dacă trebuie construit succesorul vectorului V ). La terminarea fiecărei execuţii a
procedurii , IG are fie valoarea 1 ( dacă a fost generat un nou vector V ), fie valoarea 0 ( dacă
au fost generaţi toţi vectorii V ceruţi de problema concretă ).

1.2 Algoritm de generare

procedure GEN(V , n , IG)

array V(n)

IG 1; return

endif

if [exista succesor al lui V] then V [ succesorul lui V]

else IG 0

endif

return

end

O secventă tipică de instrucţiuni care realizează generarea şi prelucrarea tuturor


vectorilor V cu o anumită proprietate este următoarea:

IG 0

do

call GEN (V , n , IG)

if IG = 0 then exit

endif

call PREL (V, n)

repeat

60
Procedura PREL asigură efectuarea unei anumite prelucrări pe baza vectorului V
curent, fără însa a modifica vreun element al sau.

În mulţi dintre algoritmii care vor fi prezentaţi, vectorii vor fi generaţi în ordine
lexicografică crescătoare. Este de remarcat faptul că aceasta corespunde strategiei
backtracking de contrucţie a algoritmilor.

2. Generarea elementelor unui produs cartezian

2.1 Noţiuni teoretice

Fie date m mulţimi ,...., unde pentru fiecare i {1 , ... , m}, =[ ]={1,
2 , ... , }. Se pune problema generarii tuturor celor elemente ale produsului
cartezian x x ... x .

Elementele produsului cartezian vor fi generate succesiv într-un vector V cu m


componente. Vectorii vor fi generaţi conform ordinii lexicografice crescătoare. Drept urmare,
se pleacă de la vectorul (1 , 1 , ... , 1). Pentru a construi seccesorul unui vector V se
procedează în modul următor: se determină cel mai mare indice i cu şi drept
succesorul al lui V se alege vectorul ( , ..., , +1, 1, ..., 1). Dacă un astfel de indice i nu
există , înseamnă că vectorul V curent este ( , , ... , ), care este cel mai mare in ordine
lexicografică şi deci procesul de generare s-a incheiat. Determinarea indicelui i se face
parcurgând elementele lui V în ordine inversă.

Se va scrie o procedură, care la fiecare apel să genereze succesorul vectorului curent.


La primul apel al funcţiei, când nu se poate vorbi despre un vector curent, deoarece nu s-a
generat încă nici unul, procedura va trebui sa realizeze initializarea vectorului cu valoarea (1,
1, ... , 1).

Pentru a şti dacă vectorul este iniţializat sau nu, se va folosi o variabilă numită
iniţializat a cărei valoare este 0 dacă vectorul nu este iniţializat şi 1 în caz contrar. Aceasta ar
putea fi declarată ca variabilă globala, dar , cum ea nu prezintă interes decăt în cadrul acestei
proceduri, ar fi preferabil să fie declarată ca variabilă locală. Pentru că valoarea ei nu trebuie
să se piardă între 2 apeluri ale procedurii, variabilă iniţializat va fi declarată de tip static. Se
va conveni ca procedura să întoarcă valoarea 1 dacă s-a reuşit generarea unui element şi
valoarea 0 în cazul în care s-a încheiat.

Procedura va avea 3 parametri formali: vectorul care conţine elementul curent al


produsului cartezian şi în care se va genera elementul următor, vectorul dimensiunilor ale
celor m mulţimi ce generează produsul cartezian.

61
În programul de mai jos procedura este apelată repetat până la generarea tuturor
elementelor produsului cartezian, care vor fi afişate la consolă.

2.2 Algoritm de generare

procedure PRODCART ( V , m , n , IG )

integer V(m), n(m)

if IG = 0 then for i = 1, m

V(i) 1

repeat

IG 1 ; return

endif

for i = n , 1 , -1

if V(i) < n(i) then V(i) V(i) +1 ; return

else V(i) 1

endif

repeat

IG 0 ; return

end

Un caz particular al problemei tratate este cel în care = = = ... = =n,


deci când trebuie generate elementele mulţimii [n , elemente care mai poartă numele de m-
combinaţii a n elemente . Evident numărul lor este .

2.3 Analiza algoritmului

62
Pentru a obţine numărul de calcule efectuat de algoritmul PRODCART , observăm că
pentru , ... , fixate, componenta îşi schimbă valoarea (mărindu-se cu o unitate sau
devenind 1) de ori, deci în total îşi schimbă valoarea de * * ... * ori. Drept
urmare tinănd cont şi de iniţializare, numărul instrucţiunilor de atribuire referitoare la
elementele vectorului V este m + + + ... + *...* . În cazul particular = = ...
= = n numărul acestor operaţii de atribuire este m + n + + ... + =m+n =
= ( ).

Pe de altă parte, pentru fiecare , ... , fixate , creşte cu o unitate de −1 ori,


fiecare asemenea creştere fiind precedată de cele m − i + 1 comparări ale componentelor
,..., cu limitele superioare , ... , . Deci numărul de comparări referitoare la
componentele vectorului V este , la care se
adaugă cele m comparări care conduc la IG=0. În cazul particular = = ... = =n
numărul acestor comparări este

(n - 1) = ( n - 1) + m=
=

Este de remarcat legătura între algoritmul prezentat şi sistemele mixte de numeraţie.


Un sistem mixt de numeraţie este definit de o infinitate de numere naturale , , ... , mai
mari sau egale cu 2, numite baze ale sistemului. Orice număr natural N se reprezintă în mod
unic sub forma

N= + + + + ... +

unde 0 pentru orice i , iar 0 dacă N 0.

În particular să consideram submulţimea A = {0, 1, ..., ... -1} de numere


naturale şi sistemul de numeraţie mixt cu bazele , ..., . Atunci orice număr N din A se
poate scrie unic sub forma :

N= ... + ... + ... + + (3)

unde 0 < , i = 1, 2, ..., m. În acest mod se stabileşte o corespondenţa biunivocă

:A [ ] [ ] ... [ ] ce este dată de :

63
(N) = ( + 1, ... , + 1) (4)

Se observă cu uşurinţa că procedura PRODCART generează vectorii V = ( , ... , )


astfel încât valorile ( - 1, ... , - 1) corespund în ordine numerelor naturale 0,1,...,
*..* - 1.

3. Generarea tuturor submulţimilor unei mulţimi

3.1.1 Noţiuni teoretice


Prima metodă foloseşte pentru reprezentarea submulţimilor vectorul caracteristic.
Drept urmare, problema enunţata se rezumă la a genera toţi vectorii V . Algoritmul
respectiv, construit cu procedura SUBM1, se deduce cu uşurinţa din procedura PRODCART.

3.1.2 Algoritm de generare

procedure SUBM1 (V, n, IG)

integer V(n)

if IG = 0 then for i = 1, n

V(i) 0

repeat

IG 1 ; return

endif

for i = n, 1, -1

if V(i) < 1 then V(i) 1; retunr

else V(i) 0

64
endif

repeat

IG 0 ; return

end

Conform observaţiei făcute anterior, se observă că valorile ataşate


vectorilor V sunt , în ordinea generării, tocmai numerele naturale 0, 1, ..., -1.

3.2.1 Noţiuni teoretice


O a doua metodă urmăreşte să genereze submulţimile în ordinea crescătoare a
numărului lor de elemente. Se va folosi reprezentarea (i’) a submulţimilor, ţinând cont şi de
faptul că nu interesează ordinea elementelor în submulţime; conform convenţiei făcute,
elementele vor apărea în vector în ordine crescătoare.

Evident, se pleacă de la vectorul V = (0, ..., 0) corespunzător mulţimii vide. Vectorii


vor fi generaţi de asemenea conform ordinii lexicografice crescătoare. Fie V = ( , ... , )
un vector căruia dorim sa îi determinăm succesorul. Pentru aceasta vom determina acel
indice i care satisface relaţiile :

< i; = i+1; ...; = n 1; =n (5)

Este evident că cel mai mic vector mai mare decât V conform ordinei lexicografice
este vectorul următor :

( , ..., , + 1, + 2, ..., + n - i + 1) (6)

care se obţine din V mărind pe cu o unitate, iar pe fiecare dintre elementele aflate la
dreapta lui se determină din precedentul prin mărirea acestuia cu o unitate.

În cazul în care nu există un indice i satisfăcând relaţiile (5), înseamnă că v = (1,


2, ..., n) deci au fost generate toate submulţimile.

65
3.2.2 Algoritm de generare

Procedura care concretizează metoda descrisă este procedura SUBM2.

procedure SUBM2 ( V , n , IG)

integer V(n)

if IG = 0 then for i = 1, n :

V(i) 0

repeat

IG 1; return

endif

for i = n , 1, -1 :

if V(i) < i then V(i) V(i) + 1

for j = i + 1, N

V(j) V(j 1) +1

repeat

return

endif

repeat

IG 0; return

66
end

Observaţie. Trecerea la o submulţime având un element mai mult decât cea


precedentă corespunde la schimbarea valorii unui element din 0 în 1. Algoritmul poate fi
modificat fără dificultate pentru a pune în evidenţă aceste treceri.

3.3.1 Noţiuni teoretice

A treia metodă de generare a tuturor submulţimilor unei mulţimi foloseşte, la fel ca


prima metodă, reprezentarea submulţimilor cu ajutorul vectorului caracteristic. Deosebirea
constă în faptul că la fiecare trecere de la un vector V {0, 1 la următorul va fi modificată o
singură componentă.

Se numeşte cod Gray o secvenţă G(n) de vectori distincţi din {0, 1 , începând cu
( 0, ..., 0 ) şi astfel încât doi vectori succesivi diferă pe o singură poziţie. G(n) se reprezintă
sub forma matricii (7) cu linii şi n coloane, unde G(1) este dat de (8).

G(n) (7) G(n + 1 ) = (9)

G(1) (8)

Codul G(n 1) se poate obţine din codul G(n) construind matricea corespunzătoare
în modul ilustrat în (9). După cum se recunoaşte uşor, se respectă condiţia ca două linii să
difere pe o singură poziţie.

Ştiind că prima linie din G(n) este (0, ..., 0) , codul G(n) este bine determinat de un
vector cu componente, unde pentru fiecare i {1, ..., }, este poziţia pe

67
care diferă liniile i şi i 1 din G(n), cu menţiunea că poziţiile ocupate de biţii 0 şi 1 sunt
numerotate de la dreapta la stânga. Din matricea (9) , interpretată ca relaţie între codurile
G(n) şi G(n ), rezultă că dacă ( , , ..., ), atunci :

(10)

Relaţiile (10) permit să deducem uşor prin inducţie după n că vectorul obţinut din
prin inversarea ordinei elementelor sale este tot . Ca urmare, relaţiile (10) se pot scrie
condensat sub forma :

(10’)

Exemplu. Pentru n = 3 , avem :

G(3) =

,1)

= (1, 2, 1, 3, 1, 2, 1)

Plecând de la relaţiile (10’), vectorului îi putem asocia un arbore binar strict, cu n


nivele, astfel încât pentru orice i {1, ..., n}, vârfurile situate pe nivelul i sunt etichetate cu
n + 1 i. Acest arbore are proprietatea că etichetele vârfurilor arborelui, considerate în
inordine, formează tocmai vectorul . De exemplu pentru n 4, se obţine arborele din
figura I.1.

3 3

2 2 2 2

68
1 1 1 1 1 1 1 1

Fig. I.1

i-1

i-2

Fig I.2

Se observă că acest arbore nu trebuie construit explicit pentru a-l parcurge în inordine.
Mai mult, iniţial putem introduce într-o stivă, în ordine de la bază la vârf, elementele
n, n − 1, ..., 1. La fiecare pas se va scoate un element din stivă ( dacă stiva este vidă, procesul
se încheie ), element care constituie poziţia ce trebuie modificată pentru a obţine următoarea
linie din G(n); dacă acest element este i > 1, atunci se vor introduce în stivă pe rînd
elementele i − 1, i − 2, ..., 2, 1, în conformitate cu algoritmul de parcurgere în inordine şi
cu figura IV.2. Mai observăm că putem reveni la numerotarea uzuală a poziţiilor ( de la
stânga la dreapta ), deoarece aceasta implică doar inversarea ordinii în care apar elementele
liniilor din G(n).

3.3.2.1 Algoritm de generare

Observaţiile de mai sus duc la procedura GRAY1, în care cei vectori căutaţi se
obţin succesiv în vectorul V.

procedure GRAY1 ( n, V, ς, IG )
integer V(n) ; stack ς

if IG = 0 then ς

for i = n, 1,-1

V(i) 0; i ς

repeat
IG ← 1; return
endif

69
if ς = then IG ← 0; return

endif

i ς; V(1) 1 V(i)

for j i 1, 1, 1

j ς
repeat
return
end

3.3.2.2 Analiza algoritmului

Procedura GRAY1 mai poate fi îmbunătaţită prin eliminarea ultimului ciclu for, ceea
ce va face ca trecerea de la un vector V la următorul să necesite un timp constant. În acest
scop, stiva ς va fi înlocuită cu un vector SUB cu n componente cu următorul conţinut:
- dacă elemetul i se află în stivă, atunci SUB(i) este elementul aflat în stivă imediat sub el
- dacă elemntul i nu se află în stiva, atunci SUB(i) = i + 1, corespunzător faptului că în
momentul în care va fi introdus în stivă, sub el se va afla i + 1.
Drept urmare se obţine procedura GRAY2 în care i este elementul din vârful stivei.

procedure GRAY2 ( n, V, SUB, i, IG)


integer V(n), SUB(n)
if IG = 0 then for j = 1, n

V(j) 0; SUB(j) j+1

repeat

i 1; IG 1; return
endif

if i = n + 1 then IG 0; return

70
endif

V(i) 1 V(i)

if i = 1 then i SUB(1); SUB 2

else SUB(i 1) SUB(i); SUB(i) i + 1; i 1

endif
return
end
Conţinutul ultimei instrucţiuni if din procedura GRAY2 poate fi uşor înteles dacă se
urmăreşte figura I.2.

3.4.1 Noţiuni teoretice


O ultimă metodă foloşeste reprezentarea (i) a submulţimilor, păstrându-se în variabila
k numărul elementelor. Elementele submulţimii vor apărea în ordine crescătoare, adică
< < ...< . Iniţial k = 0. La pasul următor vom lua k = 1 şi = 1. În continuare,
vectorii vor fi generaţi conform ordinei lexicografice crescătoare. În consecinţă, trecerea de la
un vector V = ( ) la succesorul său se va face astfel:

- dacă < n, atunci succesorul va fi ( , + 1)

- dacă = n, sunt posibile două situaţii : dacă k > 1, atunci succesorul căutat este (
+ 1 ); dacă k = 1, s-a ajuns la V = (n) şi deci au fost generate toate
submulţimile.
Spre deosebire de a doua metodă, submulţimile nu mai sunt generate în ordinea
crescătoare a numărului lor de elemente. Este însă important de observat că trecerea de la un
vector la succesorul său necesită timp constant. Procedura corespunzătoare metodei descrise
este procedura SUBM3.

3.4.2 Algoritm de generare

procedure SUBM3(V, n, IG, k)


integer V(n)

if IG = 0 then k 0; IG 1; return

71
endif

if k = 0 then k 1; V(1) 1; return


endif

if V(k) < n then k k + 1; V(k) V(k) + 1; return

endif

if k = 1 then IG 0; return

else k k 1; V(k) V(k) + 1; return


endif
return
end

4. Generarea aranjamentelor

4.1.1 Noţiuni teoretice

Metoda 1. Se generează aranjamentele de n elemente luate câte m, cu repetiţie.


Generarea submulţimii se reduce la generarea unei alte submulţimi având un element
mai puţin decât în etapa curentă.
La apelul funcţiei recursive se porneşte de la ultima poziţie ( indice m − 1 ).
Apelurile recursive ne duc spre indici mai mici.

4.1.2. Algoritm de generare

Se obţine astfel procedura ARANJ1.

procedure ARANJ1 ( k, n, m )

integer j, k

if k = -1 then afişează

else for i = 0, n

72
indici[k] ← j ;

call ARANJ1(k − 1)

repeat

endif

return

end

4.2.1 Noţiuni teoretice

Metoda 2. Această metodă va genera aranjamente în ordine lexicografică, adică


folosind metoda backtracking. Se pleacă de la a = (1, 2, ..., m). Fie a = ( , ..., ) un
aranjament oarecare. Pentru determinarea succesorului său, se va determina mai întâi cel mai
mare indice i cu proprietatea că poate fi mărit. Un element poate fi mărit dacă toate
valorile + 1, ..., n cu care ar putea fi înlocuit nu sunt disponibile ; pentru a efectua uşor
aceste verificări este utilă introducerea unui vector DISP cu n elemente, unde DISP(i) este 0
sau 1 după cum valoarea i este sau nu disponibilă, adică apare sau nu în vectorul a curent.

Se observă că în procesul căutării ( în ordine descrescătoare ) a indicelui i cu


proprietatea menţionată, ori de câte ori se ajunge la un element, valoarea sa trebuie făcută
disponibilă ( indiferent dacă este vorba de indicele i căutat sau de un indice mai mare decât
el ).

În momentul în care a fost determinat indicele i, elementele , , ..., vor primi


ca valori cele mai mici numere disponibile, bineînţeles în ordine crescătoare, deoarece
vectorul a’ căutat este cel mai mic vector cu elemente distincte mai mare decât a în ordine
lexicografică. Dacă nu există un indice i cu proprietatea menţionată, înseamnă că s-a ajuns la
vectorul ( n − m + 1, n − m + 2, ..., n), deci procesul generării s-a încheiat. Se obţine astfel
procedura ARANJ2.

4.2.2. Algoritm de generare

73
procedure ARANJ2(a, n, m, IG, DISP)

integer a(m), DISP(n)

if IG = 0 then for i = 1, m

←i; ←1

repeat

for i = m + 1, n

←0

repeat

IG ← 1; return

endif

for i = m, 1, −1

←0

for j = + 1, n

if = 0 then /* se contruiesc noile valori ,..., */

←j; ← 1; k ← 0

for l = i + 1, m

do

k←k+1

until =0

←k; ←1

repeat

return

endif

repeat

repeat

74
IG ← 0 ; return

end

Concluzii Finale

În această lucrare am considerat totdeauna că A = [n] = {1,...,n} datorită


corespondenţei .

Submulţimile generate au fost de următoarele două tipuri:

- submulţimi în care este importantă ordinea în care apar elementele;

- submulţimi în care nu contează ordinea în care apar elementele.

Toate generările ce au fost prezentate în această lucrare au avut un caracter iterativ,


fiecare element fiind dedus din anteriorul său.

Aplicaţia a fost implementată în mediul de programare Borland C++ 3.1.

În urma rulării primului program s-au obţinut elementele unui produs cartezian.
Elementele produsului cartezian au fost generate succesiv într-un vector V cu m componente.

Cel de-al doilea program a implementat un algoritm de generare a tuturor grupărilor


de m elemente distincte din mulţimea [n] (două grupări diferă fie prin natura lor, fie prin
ordinea elementelor). Astfel au fost generate aranjamente de n elemente luate câte m, cu
repetiţie.

75
În total au fost expuse zece mari modalităti de efectuare a diferite operaţii asupra
elementelor unor mulţimi. La fiecare generare au fost analizate atât algoritmul matematic, cât
şi cel din mediul de programare.

Bibliografie

- Leon Livovschi, Horia Georgescu – "Sinteza şi analiza algoritmilor", Editura Ştiinţifică


Bucureşti, 1986

- Alexandru Ionică, “Proiectarea şi analiza algoritmilor”, Editura Mirton, Timişoara, 1992

- Alexandru Ionică, “Algoritmi de prelucrare mulţimi discrete finite”, Editura Mirton,


Timişoara, 1995

- Alexandru Ionică, “Metode de proiectare şi analiză a algoritmilor recursivi”, Editura


Tehnică Militară, Bucureşti, 2001

- Alexandru Ionică, Michal Tuska, Elena Giorgiana Ionică, Cristian Alexandru Ionică,
“Recursivitate si sortare”, Vol I, Editura IVAN KRASKO, Nadlac-Arad-România, 2005

- http://www.einformatica.ro/

- http://www.infobytedb.ro/

76
77