AU
Tematica
1 Elemente de complexitatea algoritmilor si teoria
1.1 Notatii asimptotice . . . . . . . . . . . . . . . . .
1.2 Definitii generale privind grafurile . . . . . . . . .
1.3 Reprezentarea grafurilor . . . . . . . . . . . . . .
1.4 Grade . . . . . . . . . . . . . . . . . . . . . . . .
1.5 Conexitate . . . . . . . . . . . . . . . . . . . . . .
1.6 Parcurgerea grafurilor . . . . . . . . . . . . . . .
grafurilor
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
2 Metoda Greedy
2.1 Descrierea metodei. Algoritmi generali . . . . . . .
2.2 O problema de maxim/minim . . . . . . . . . . . .
2.3 Memorarea optimala a textelor pe benzi . . . . . .
2.4 Arbori partiali de cost minim . . . . . . . . . . . .
2.5 Distante si drumuri minime. Algoritmul lui Dijkstra
2.6 Fluxuri maxime n retele . . . . . . . . . . . . . . .
3 Metoda Divide et Impera
3.1 Descrierea metodei. Algoritm general
3.2 Problema turnurilor din Hanoi . . . .
3.3 Cautarea binara . . . . . . . . . . . .
3.4 Sortarea prin interclasare (mergesort)
3.5 Sortarea rapida (quicksort) . . . . . .
3.6 O problema de acoperire . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6
6
11
15
17
19
23
.
.
.
.
.
.
32
32
35
37
39
45
52
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
75
75
77
79
84
88
92
4 Metoda program
arii dinamice
4.1 Descrierea metodei. Algoritm general . . . . . . . .
4.2 Subsir crescator de lungime maxima . . . . . . . . .
4.3 Matricea drumurilor. Algoritmul Roy-Warshall . . .
4.4 Distante si drumuri minime. Algoritmul Roy-Floyd
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
95
95
96
98
103
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
TEMATICA
5 Metoda Backtracking
5.1 Descrierea metodei. Algoritmi generali . . . . . . . . . . . .
5.2 Problema celor n dame . . . . . . . . . . . . . . . . . . . . .
5.3 Colorarea grafurilor . . . . . . . . . . . . . . . . . . . . . . .
2
107
. 107
. 115
. 117
Evaluare
Prezenta: 10%
Activitate laborator: 30% (Programe si probleme din Temele de laborator)
Teme de casa: 10% (Programe si probleme suplimentare)
Examen final: 50% (Proba scrisa: teorie, algoritmi -cu implementaresi probleme)
Bibliografie
[1] A.V. Aho, J.E. Hopcroft, J.D. Ullman, Data Structures and Algorithms, AddisonWesley, Massachusetts, 2009.
[2] Gh. Barbu, V. P
aun, Programarea n limbajul C/C++, Editura Matrix Rom, Bucuresti, 2011.
[3] Gh. Barbu, V. P
aun, Calculatoare personale si programare n C/C++, Editura Didactic
a si Pedagogic
a, Bucuresti, 2005.
[4] Gh. Barbu, I. V
aduva, M. Bolosteanu, Bazele informaticii, Editura Tehnica, Bucuresti, 1997.
[5] C. Balc
au, Combinatoric
a si teoria grafurilor, Editura Universitatii din Pitesti,
Pitesti, 2007.
[6] O. Basc
a, L. Livovschi, Algoritmi euristici, Editura Universitatii din Bucuresti, Bucuresti, 2003.
[7] E. Cerchez, M. Serban, Programarea n limbajul C/C++ pentru liceu. Vol. 2: Metode
si tehnici de programare, Ed. Polirom, Iasi, 2005.
[8] E. Ciurea, L. Ciupal
a, Algoritmi. Introducere n algoritmica fluxurilor n retele, Editura Matrix Rom, Bucuresti, 2006.
[9] T.H. Cormen, Algorithms Unlocked, MIT Press, Cambridge, 2013.
[10] T.H. Cormen, C.E. Leiserson, R.L. Rivest, C. Stein, Introduction to Algorithms, MIT
Press, Cambridge, 2009.
[11] C. Croitoru, Tehnici de baz
a n optimizarea combinatorie, Editura Universitatii Al.
I. Cuza, Iasi, 1992.
[12] N. Dale, C. Weems, Programming and problem solving with JAVA, Jones & Bartlett
Publishers, Sudbury, 2008.
[13] D. Du, X. Hu, Steiner Tree Problems in Computer Communication Networks, World
Scientific Publishing Co. Pte. Ltd., Hackensack, 2008.
[14] S. Even, Graph Algorithms, Cambridge University Press, Cambridge, 2012.
5
[15] H. Georgescu, Tehnici de programare, Editura Universitatii din Bucuresti, Bucuresti,
2005.
[16] C.A. Giumale, Introducere n analiza algoritmilor. Teorie si aplicatii, Ed. Polirom,
Iasi, 2004.
[17] F.V. Jensen, T.D. Nielsen, Bayesian Networks and Decision Graphs, Springer, New
York, 2007.
[18] D. Jungnickel, Graphs, Networks and Algorithms, Springer, Heidelberg, 2013.
[19] D.E. Knuth, The Art Of Computer Programming. Vol. 4A: Combinatorial Algorithms, Addison-Wesley, Massachusetts, 2011.
[20] B. Korte, J. Vygen, Combinatorial Optimization. Theory and Algorithms, Springer,
Heidelberg, 2012.
[21] L. Livovschi, H. Georgescu, Sinteza si analiza algoritmilor, Editura Stiintific
a si
Enciclopedica, Bucuresti, 1986.
[22] D. Logofatu, Algoritmi fundamentali n C++: Aplictii, Ed. Polirom, Iasi, 2007.
[23] D. Lucanu, M. Craus, Proiectarea algoritmilor, Ed. Polirom, Iasi, 2008.
[24] D.R. Popescu, Combinatoric
a si teoria grafurilor, Societatea de Stiinte Matematice
din Rom
ania, Bucuresti, 2005.
[25] N. Popescu, Data structures and algorithms using Java, Editura Politehnica Press,
Bucuresti, 2008.
[26] V. Preda, C. Balc
au, Entropy optimization with applications, Editura Academiei
Rom
ane, Bucuresti, 2010.
[27] R. Stephens, Essential Algorithms: A Practical Approach to Computer Algorithms,
Wiley, Indianopolis, 2013.
[28] S. T
anasa, C. Olaru, S. Andrei, Java de la 0 la expert, Ed. Polirom, Iasi, 2007.
[29] T. Toadere, Grafe. Teorie, algoritmi si aplicatii, Editura Albastr
a, Cluj-Napoca,
2002.
[30] I. Tomescu, Combinatoric
a si teoria grafurilor, Tipografia Universitatii din Bucuresti, Bucuresti, 1978.
[31] I. Tomescu, Probleme de combinatoric
a si teoria grafurilor, Editura Didactica si
Pedagogic
a, Bucuresti, 1981.
[32] I. Tomescu, Data structures, Editura Universitatii din Bucuresti, Bucuresti, 2004.
[33] ***, Handbook of combinatorics, edited by R.L. Graham, M. Grotschel and L. Lovasz,
Elsevier, Amsterdam, 1995.
[34] ***, Handbook of discrete and combinatorial mathematics, edited by K.H. Rosen,
J.G. Michaels, J.L. Gross, J.W. Grossman and D.R. Shier, CRC Press, Boca Raton,
2000.
Tema 1
Elemente de complexitatea
algoritmilor si teoria grafurilor
1.1
Notatii asimptotice
Vom defini un tip de functii care reprezinta un bun model pentru descrierea
complexitatii temporale a unui algoritm, adica a dependentei timpului de
executie fata de dimensiunea datelor de intrare.
Definitia 1.1.1. O functie asimptotic pozitiv
a (prescurtat a.p.) este o
functie f : N \ A R a..
A N este o multime finita;
n0 N \ A astfel ncat f (n) > 0, n n0 .
Observatia 1.1.1. De cele mai multe ori, multimea A este de forma
A=
{0, 1, 2, . . . , k} , unde k N.
{z
}
|
(3n4 + n + 3) n 5
Exemplul 1.1.1. Functia f : D R, f (n) =
, unde
(5n + 1)(n 8)
D = {n N | n 5, n 6= 8}, este asimptotic pozitiva, deoarece D = N \ A
cu A = {0, 1, 2, 3, 4, 8} (multime finita) si f (n) > 0, n 9.
ln(n5 + 1) n
, nu este
(n 1)(n 6)
asimptotic pozitiva, deoarece (n 1)(n 6) > 0, n 7, dar lim [ln(n5 +
Exemplul 1.1.2. Functia g : N \ {1, 6} R, g(n) =
Figura 1.1.1:
Figura 1.1.2:
Figura 1.1.3:
10
f (n)
(3n4 + n + 3) n 5
lim
= lim
n n3
n n3 (5n + 1)(n 8)
q
1 n5
n4 n 3 + n13 + n34
= 0,
= lim
n
n5 (5 + n1 )(1 n8 )
rezulta ca f (n) = O (n3 ), dar f (n) 6= (n3 ) si f (n) 6= (n3 ).
Deoarece
f (n)
(3n4 + n + 3) n 5
lim
= lim
n n2
n n2 (5n + 1)(n 8)
q
3
1
4
1 n5
n n 3 + n3 + n4
= lim
= ,
n
n4 (5 + n1 )(1 n8 )
rezulta ca f (n) = (n2 ), dar f (n) 6= O (n2 ) si f (n) 6= (n2 ).
Deoarece
f (n)
(3n4 + n + 3) n 5
lim
= lim 2
n n2 n
n n
n(5n + 1)(n 8)
q
n4 n 3 + n13 + n34
1 n5
3
,
= lim
=
8
1
n
5
n4 n(5 + n )(1 n )
rezulta ca f (n) = (n2 n), deci f (n) = O (n2 n) si f (n) = (n2 n).
11
1.2
12
13
e3
1
e1
e2
4
e4
e7
e8
e9
e5
e6
Figura 1.2.1:
Figura 1.2.2:
14
Figura 1.2.3:
Pentru graful orientat din Exemplul 1.2.2, subgraful generat de submultimea de arce {(2, 3), (5, 4)} are reprezentarea din Figura 1.2.4, iar graful
partial generat de aceeasi submultime de arce are reprezentarea din Figura
1.2.5.
Definitia 1.2.12. Fie G = (V, E) un graf (neorientat sau orientat) si U V
o submultime de noduri a.. U 6= V . Subgraful obtinut din G prin
eliminarea nodurilor multimii U este subgraful G \ U = (V \ U, F ),
unde F este colectia tuturor muchiilor sau arcelor din E ce nu sunt incidente
cu niciun nod din U.
15
Figura 1.2.4:
Figura 1.2.5:
1.3
Reprezentarea grafurilor
In continuare descriem cateva forme de reprezentare (memorare) a grafurilor n informatica. Dintre aceste forme, cea mai utilizata este matricea de
adiacenta.
Definitia 1.3.1. Fie G = (V, E) un graf (neorientat sau orientat) unde
V = {v1 , . . . , vn } si E = {e1 , . . . , em }. Matricea de adiacenta
asociata
grafului G este matricea A = (aij )i,j=1,n definita prin
aij = numarul de muchii sau de arce ek E de la nodul vi la nodul vj (adica
muchii de forma ek = [vi , vj ], respectiv arce de forma ek = (vi , vj )),
i, j {1, . . . , n}.
Observatia 1.3.1. a) Daca graful neorientat G = (V, E) este simplu, atunci
1, daca vi si vj sunt adiacente (adica [vi , vj ] E),
aij =
0, n caz contrar.
16
0 1 0 1 0 0
1 1 0 0 1 0
0 0 0 0 0 2
A=
1 0 0 0 3 0 ,
0 1 0 3 0 0
0 0 2 0 0 0
iar matricea de adiacenta asociata
0
0
A=
1
0
0
1 0 0 0
0 1 1 1
1 0 0 0
.
0 0 0 0
0 0 1 0
17
L(1)
= {3}, L(2)
= {1, 3}, L(3)
= {2}, L(4)
= {2, 5}, L(5)
= {2}.
Evident, pentru grafurile neorientate notiunile de succesor direct si predecesor
direct coincid, fiind si sinonime cu notiunile de vecin sau adiacent.
Observatia 1.3.5. Alegerea uneia sau alteia dintre formele de reprezentare a
grafurilor descrise mai sus depinde de eficienta si de usurinta implementarii
operatiilor necesare de prelucrare a acestor forme, deci de tipul problemei
modelate prin grafuri si de algoritmul de rezolvare utilizat.
1.4
Grade
18
gradul de ie
sire (semigradul exterior) al lui x, notat d+
G (x) =
d+ (x), reprezinta numarul de arce e E incidente cu x spre exterior;
gradul de intrare (semigradul interior) al lui x, notat d
G (x) =
d (x), reprezinta numarul de arce e E incidente cu x spre interior;
gradul (total al) lui x, notat dG (x) = d(x), este
d(x) = d+ (x) + d (x).
Exemplul 1.4.1. Pentru graful neorientat din Exemplul 1.2.1, gradele nodurilor sunt: d(1) = 2, d(2) = 4, d(3) = 2, d(4) = 4, d(5) = 4, d(6) = 2.
Pentru graful orientat din Exemplul 1.2.2, gradele nodurilor sunt:
d+ (1) = 1,
d+ (2) = 3,
d+ (3) = 2,
d+ (4) = 0,
d+ (5) = 1,
d (1) = 1,
d (2) = 2,
d (3) = 1,
d (4) = 2,
d (5) = 1,
d(1) = 2,
d(2) = 5,
d(3) = 3,
d(4) = 2,
d(5) = 2.
n
P
j=1
n
P
aij , d (vi ) =
j=1
{1, . . . , n}.
n
P
j=1
aji , i
xV
1.5
19
Conexitate
20
21
Exemplul 1.5.2. Graful neorientat din Exemplul 1.2.1 nu este conex, deoarece
nu exista lanturi ntre nodurile 1 si 3. Graful orientat din Exemplul 1.2.2
este conex, dar nu este tare-conex, deoarece nu exista drum de la nodul 4 la
nodul 1 (desi exista drum de la nodul 1 la nodul 4!).
Definitia 1.5.3. a) O component
a conex
a a unui graf (orientat sau
neorientat) G = (V, E) este un subgraf G[U] generat de o submultime
U V de noduri cu proprietatea ca G[U] este conex si maximal cu
aceasta proprietate (n raport cu incluziunea), adica pentru orice nod
x V \ U subgraful G[U {x}] nu mai este conex.
b) O component
a tare-conex
a a unui graf orientat G = (V, E) este un
subgraf G[U] generat de o multime U V de noduri cu proprietatea
ca G[U] este tare-conex si maximal cu aceasta proprietate (n raport cu
incluziunea), adica pentru orice noduri x1 , x2 , . . . , xp V \ U subgraful
G[U {x1 , x2 , . . . , xp }] nu mai este tare-conex.
Observatia 1.5.6. Un graf este conex daca si numai daca are o singura componenta conexa. Un graf orientat este tare-conex daca si numai daca are o
singura componenta tare-conexa. Numarul de componente tare-conexe ale
unui graf orientat este mai mare sau egal decat numarul de componente
conexe ale acelui graf, deoarece orice componenta tare-conexa este inclusa
ntr-o componenta conexa (conform definitiei anterioare si Observatiei 1.5.4).
Observatia 1.5.7. Orice nod izolat x genereaza o componenta conexa si o
componenta tare-conexa, ambele avand forma G[{x}] = ({x}, ).
Propozitia 1.5.1. a) Fie G[V1 ], . . . , G[Vk ] componentele conexe (diferite)
ale unui graf G = (V, E). Atunci {V1 , . . . , Vk } este o partitie a multimii
V (adica Vi 6= i, Vi Vj = i 6= j, V1 Vk = V ).
b) Fie G[V1 ], . . . , G[Vr ] componentele tare-conexe (diferite) ale unui graf
orientat G = (V, E). Atunci {V1 , . . . , Vr } este de asemenea o partitie
a multimii V .
Exemplul 1.5.3. Componentele conexe ale grafului neorientat din Exemplul
1.2.1 sunt generate de submultimile de noduri V1 = {1, 2, 4, 5} si V2 = {3, 6},
deci acel graf are 2 componente conexe. Componentele tare-conexe ale grafului orientat din Exemplul 1.2.2 sunt generate de submultimile de noduri
V1 = {1, 2, 3}, V2 = {4} si V3 = {5}, deci acel graf are 3 componente tareconexe.
Observatia 1.5.8. Submultimile de muchii sau arce ale componentelor conexe
ale unui graf formeaza de asemenea o partitie a multimii de muchii sau arce
22
a grafului (deoarece pentru orice muchie e = [x, y] sau arc e = (x, y) nodurile
x si y se afla ntr-o aceeasi componenta conexa si aceasta componenta va
contine si pe e). Afirmatia nu mai este valabila pentru componentele tareconexe. De exemplu, pentru graful din Exemplul 1.2.2 arcul (5, 4) nu apartine
nici-unei componente tare-conexe.
Definitia 1.5.4.
b) O p
adure este un graf fara cicluri.
c) Un arbore partial al unui graf G = (V, E) este un graf partial al lui
G ce este arbore (adica un arbore T = (V, F ) cu F E).
Observatia 1.5.9. Arborii si padurile sunt grafuri simple (deoarece orice bucla
este un ciclu si orice doua muchii sau arce multiple formeaza un ciclu).
Observatia 1.5.10. Componentele conexe ale unei paduri sunt arbori.
Exemplul 1.5.4. Graful neorientat din Exemplul 1.2.1 nu este padure (deoarece are cicluri), deci nici arbore. Graful sau partial reprezentat n Figura
1.5.1 este o padure (avand doua componente conexe arbori). Graful orientat
din Exemplul 1.2.2 nu este arbore (deoarece are cicluri). Doi arbori partiali
ai sai sunt reprezentati n Figura 1.5.2.
1
e1
e2
e4
e5
6
Figura 1.5.1:
1
5
Figura 1.5.2:
2
5
1.6
23
Parcurgerea grafurilor
Prin parcurgerea unui graf se ntelege o metoda sistematica de vizitare succesiva a nodurilor sale (n vederea prelucrarii informatiilor atasate n structura
de date modelata prin graful dat).
Definitia 1.6.1. Fie G = (V, E) un graf si x V un nod arbitrar fixat.
Parcurgerea n ad
ancime (DF, depth first) a grafului G pornind din
nodul x, numit si r
ad
acin
a a acestei parcurgeri, consta n:
se vizitez
a nodul x, acesta devine nod curent;
daca nodul curent vi are succesori directi (adica noduri vj pentru care
exista muchie sau arc de la vi la vj ) nevizitati, atunci se viziteaza primul
astfel de nod vj ; nodul vj devine nod curent si se continua procedeul de
parcurgere pornind din acest nod;
daca nodul curent vj nu mai are succesori directi nevizitati, atunci se
revine la nodul predecesor direct vi (cel din care a fost vizitat); nodul vi
redevine nod curent si se continua procedeul de parcurgere pornind din
acest nod;
daca nodul curent nu mai are nici succesori directi nevizitati, nici predecesor direct (deci este chiar radacina x), atunci parcurgerea se ncheie.
Observatia 1.6.1. Pentru parcurgerea DF, considerand cate o muchie sau un
arc de la fiecare nod curent vi la primul sau succesor direct nevizitat vj (care
va deveni urmatorul nod curent) se obtine un arbore, numit arbore DF.
Exemplul 1.6.1. Pentru graful din Exemplul 1.2.2, parcurgerea n adancime
pornind din nodul 2 este
DF (2) : 2, 3, 1, 4, 5
(considerand ca ordinea dintre succesorii directi ai fiecarui nod este ordinea
crescatoare). Arborele DF corespunzator acestei parcurgeri este reprezentat
n Figura 1.6.1.
Pentru acelasi graf, parcurgerea DF pornind din nodul 3 este
DF (3) : 3, 1, 2, 4, 5,
iar arborele DF corespunzator este reprezentat n Figura 1.6.2.
Prezentam n continuare doi algoritmi, unul recursiv si altul nerecursiv,
pentru implementarea parcurgerii n adancime.
24
Figura 1.6.1:
3
Figura 1.6.2:
25
pentru orice nod i din parcurgerea DF . Descrierea n pseudocod a algoritmului recursiv de parcurgere n adancime pornind din nodul x are urmatoarea
forma.
DF RECURSIV(x) :
VIZITEAZA(x);
// se viziteaz
a x, de exemplu se afi
seaz
a x
V IZ[x] 1;
// x a fost vizitat
for y = 1, n do
if (axy 1) and (V IZ[y] = 0) then
// y este primul succesor direct nevizitat al lui x
T AT A[y] x;
DF RECURSIV(y);
// se continu
a parcurgerea DF
// din nodul y
26
VIZ[x]=1;
for(y=1;y<=n;y++)
if ((A[x][y]>=1)&&(VIZ[y]==0))
{ TATA[y]=x;
DF_recursiv(y);
}
}
void main()
{ int x,i;
clrscr();
citire_graf();
for(i=1;i<=n;i++)
{ VIZ[i]=0; TATA[i]=0;
}
cout<<"Nodul de pornire: x=";cin>>x;
cout<<"Parcurgerea DF: ";
DF_recursiv(x);
cout<<"\nArborele DF este dat de vectorul TATA: ";
for (i=1;i<=n;i++) cout<<TATA[i]<<" ";
getch();
}
Exemplul 1.6.2. Pentru graful din Exemplul 1.2.2, fisierul de intrare graf2.dat
folosit la citirea grafului n programul anterior contine datele:
5 7
//5 noduri si 7 arce
1 2
//arcul (1, 2)
2 3
//arcul (2, 3)
2 4
//arcul (2, 4)
2 5
//arcul (2, 5)
3 1
//arcul (3, 1)
3 2
//arcul (3, 2)
5 4
//arcul (5, 4).
Algoritmul 1.6.2 (parcurgerea DF, nerecursiv). Fie din nou G = (V, E)
un graf avand multimea de noduri V = {1, . . . , n} si matricea de adiacenta
A = (aij )i,j=1,n . Fie x V un nod arbitrar fixat. Pentru implementarea nerecursiva a parcurgerii DF (x) vom utiliza vectorii V IZ si T AT A cu aceleasi
semnificatii ca n algoritmul anterior, un vector URM cu semnificatia
URM[i] = urmatorul succesor direct al nodului i,
si o structura de tip stiv
a S, memorata ca un vector, ce contine nodurile
vizitate si n curs de prelucrare, adica de vizitare a tuturor succesorilor.
Descrierea n pseudocod a algoritmului are urmatoarea forma.
27
DF(x) :
VIZITEAZA(x);
// se viziteaz
a x, de exemplu se afi
seaz
a x
V IZ[x] 1;
// x a fost vizitat
T AT A[x] 0;
varf 1; S[varf ] x;
// x se introduce ^
n v^
arful stivei
while (varf > 0) do
// stiva este nevid
a
i S[varf ];
// i este nodul din v^
arful stivei
j URM[i] + 1;
// j va fi urm
atorul succesor direct
// nevizitat al lui i, dac
a exist
a
while (aij = 0) and (j n) do j j + 1;
if (j > n) then
// nodul i nu mai are succesori direct
i nevizitat
i
varf varf 1;
// s-a ^
ncheiat prelucrarea lui i
//
si ^
l elimin
am din stiv
a
else
URM[i] j;
// j este urm
atorul succesor direct
// al lui i
if (V IZ[j] = 0) then
// j nu a fost vizitat
VIZITEAZA(j);
// se viziteaz
a j
V IZ[j] 1;
// j a fost vizitat
T AT A[j] i;
varf varf + 1;
S[varf ] j;
// se introduce j ^
n v^
arful stivei
// stiva este vid
a, nu mai exist
a noduri neprelucrate,
// parcurgerea este
^ncheiat
a.
Observatia 1.6.2. Pentru un graf cu n noduri si m muchii sau arce, implementarea anterioara a parcurgerii DF are complexitatea O (n2 ), deoarece
oricare din cele n noduri este vizitat (deci introdus si extras din stiva) cel
mult cate o data, iar cautarea succesorilor directi j nevizitati ai fiecarui nod
i extras din stiva se efectueaza n cel mult n pasi, prin parcurgerea liniei i
din matricea de adiacenta.
Daca graful este memorat prin intermediul listelor de adiacenta, atunci
cautarea succesorilor directi j nevizitati ai fiecarui nod i extras din stiva se
efectueaza, prin parcurgerea lor succesiva, n exact d(i) (pentru graf neorientat) sau d+ (i) (pentru graf orientat) pasi. Cum, conform Propozitiei 1.4.2,
P
P +
d(x) = 2m si
d (x) = m, obtinem ca n acest caz parcurgerea DF
xV
xV
28
unde functia DF(i) este cea din Algoritmul 1.6.1 sau cea din Algoritmul
29
30
Figura 1.6.3:
3
2
1
Figura 1.6.4:
31
BF(x) :
VIZITEAZA(x);
V IZ[x] 1;
T AT A[x] 0;
coada 1;
// nodurile se adaug
a la S pe pozit
ia "coada "
varf 1;
//
si se elimin
a de pe pozit
ia "varf "
S[coada] x;
while (varf coada) do
// coada este nevid
a
i S[varf ];
j URM[i] + 1;
while (aij = 0) and (j n) do j j + 1;
if (j > n) then
varf varf + 1;
else
URM[i] j;
if (V IZ[j] = 0) then
VIZITEAZA(j);
V IZ[j] 1;
T AT A[j] i;
coada coada + 1;
S[coada] j;
Observatia 1.6.7. Analog parcurgerii DF, implementarea anterioara a parcurgerii BF are complexitatea O (n2 ), iar daca graful este memorat prin
intermediul listelor de adiacenta, atunci complexitatea este O (n + m).
Observatia 1.6.8. Observatiile 1.6.3, 1.6.4 si 1.6.5 si algoritmii corespunzatori
raman valabile daca nlocuim parcurgerea DF cu parcurgerea BF.
Tema 2
Metoda Greedy
2.1
33
GREEDY1(A, n, B) :
B ;
for i = 1, n do
x ALEGE(A, i, n);
if SOLUTIE POSIBILA (B, x) then
B B {x};
Observatia 2.1.1.
Functia ALEGE(A, i, n) returneaza un element x = aj {ai , . . . , an }
si efectueaza interschimbarea ai aj ;
Functia SOLUTIE POSIBILA(B, x) verifica daca B{x} este solutie
posibila a problemei.
Functia ALEGE este cea mai dificil de realizat, deoarece trebuie sa
implementeze criteriul conform caruia alegerea la fiecare pas a cate
unui candidat sa conduca n final la obtinerea solutiei optime.
Algoritmul 2.1.2 (Metoda Greedy, varianta a II-a).
Metoda e asemanatoare primeia, cu exceptia faptului ca se stabileste de
la nceput ordinea n care trebuie analizate elementele din A.
GREEDY2(A, n, B) :
PRELUCREAZA (A, n);
B ;
for i = 1, n do
if SOLUTIE POSIBILA (B, ai ) then
B B {ai };
Observatia 2.1.2. Prin apelul procedurii PRELUCREAZA(A, n) se efectueaza o permutare a elementelor multimii A, stabilind ordinea de analiza a
acestora. Aceasta este procedura cea mai dificil de realizat.
Observatia 2.1.3.
Metoda Greedy nu cauta sa determine toate solutiile posibile si apoi
sa aleaga pe cea optima conform criteriului de optimizare dat (ceea ce
ar necesita n general un timp de calcul si spatiu de memorie mari), ci
consta n a alege pe rand cate un element, urmand sa-l nghita eventual n solutia optima. De aici vine si numele metodei (Greedy = lacom).
34
bB\{b0 }
// adev
arat
// fals
35
2.2
O problem
a de maxim/minim
b)
n
X
i=1
k=1
n
X
k=1
Sn
k=1
ak bnk+1 = min
Sn
n
X
k=1
ak b(k) .
n
X
k=1
ak b(k) .
n
X
k=1
ak b(k) ,
(2.2.1)
(2.2.2)
36
(2.2.3)
=
,
(1) (2) . . . (j) . . . (i) . . . (n)
adica
(k) = (k), k cu k 6= i si k 6= j,
(i) = (j),
(j) = (i).
Calculam
S() S( ) =
n
X
k=1
ak b(k)
n
X
k=1
ak b (k) =
k=1
T
inand seama de relatia (2.2.1), obtinem ca
n
X
k=1
ak bk = max
Sn
n
X
k=1
ak b(k) .
37
cel mai mic dintre termenii sirului (bj )j=1,n neales la pasii precedenti.
b) La fiecare pas (pentru obtinerea celor n termeni ai sumei) se vor lua:
cel mai mic (mare) dintre termenii sirului (ai )i=1,n neales la pasii
precedenti;
cel mai mare (mic) dintre termenii sirului (bj )j=1,n neales la pasii
precedenti.
2.3
Memorarea optimal
a a textelor pe benzi
k
X
i=1
38
Tmediu =
n
X
Tk
k=1
n X
k
X
k=1 i=1
Lp(i)
.
n X
k
X
n X
k
X
Lp(i) . Atunci
k=1 i=1
Lp(i) =
k=1 i=1
n
X
k=1
Lp(1) + Lp(2) + + Lp(k) =
= Lp(1) + Lp(1) + Lp( 2) + + Lp(1) + Lp(2) + + Lp(n) =
= n Lp(1) + (n 1) Lp(2) + + 2 Lp(n1) + 1 Lp(n) =
n
X
(n k + 1) Lp(k) .
=
k=1
n
X
k=1
n
X
k=1
(n k + 1) Le(k) =
n
X
k=1
(n k + 1) Lk =
Lk (n k + 1).
39
La fiecare pas este ales textul de lungime minima dintre cele ramase la
pasii precedenti, care va fi apoi memorat pe banda;
Deci textele vor fi memorate pe banda n ordinea crescatoare a lungimilor lor.
2.4
Definitia 2.4.1. Un graf ponderat este o pereche (G, c), unde G = (V, E)
este un graf iar c : E R este o functie numita pondere (cost). Pentru
orice e E, c(e) se numeste ponderea (costul) muchiei sau arcului e.
Definitia 2.4.2. Fie (G, c) un graf ponderat, G = (V, E).
a) Daca H = (U, F ) este un subgraf al lui G, atunci costul (ponderea)
lui H este
X
c(H) =
c(e)
eF
40
(2.4.1)
41
42
30
50
20
60
70
70
110
100
90
120
150
80
40
10
100
30
130
10
Figura 2.4.1:
Aplicarea Algoritmului Kruskal este evidentiata n urmatorul tabel:
Pas
1
2
3
4
5
6
7
8
9
Muchia selectata
[5, 8]
[3, 6]
[1, 2]
[8, 9]
[2, 3]
[2, 5]
[4, 6]
[7, 8]
[4, 10]
Costul ei
10
20
30
30
50
60
90
100
120
Arborele partial de cost minim obtinut este reprezentat n Figura 2.4.2. Costul acestui APM este de 510.
1
30
50
3
20
60
90
120
5
10
100
30
10
Figura 2.4.2:
Aplicarea Algoritmului Prim pentru acelasi graf este evidentiata n urmatorul tabel:
43
Muchia selectata
[1, 2]
[2, 3]
[3, 6]
[2, 5]
[5, 8]
[8, 9]
[6, 4]
[8, 7]
[4, 10]
Costul ei
30
50
20
60
10
30
90
100
120
Nodul selectat
1
2
3
6
5
8
9
4
7
10
Arborele partial de cost minim obtinut este deci acelasi cu cel obtinut
prin aplicarea Algoritmului Kruskal.
Observatia 2.4.2. Algoritmii Kruskal si Prim sunt specifici metodei de
programare Greedy. Algoritmul Kruskal selecteaza muchii, n ordinea
crescatoare a costurilor, subgrafurile induse pe parcurs de acestea nefiind
neaparat conexe. Algoritmul Prim selecteaza muchii si noduri, nu neaparat
n ordinea crescatoare a costurilor muchiilor, iar subgrafurile induse pe parcurs de muchiile selectate sunt conexe.
In implementari optime, se poate arata ca Algoritmul Kruskal are complexitatea O (m ln n) (fiind necesara sortarea muchiilor dupa cost), iar Algoritmul Prim are complexitatea O (n2 ) n cazul memorarii grafului prin matricea de adiacenta (o astfel de implementare va fi prezentata n continuare),
unde n si m reprezinta numerele de noduri, respectiv de muchii ale grafului
dat. Graful fiind conex, m n 1.
Pentru grafuri simple, m n(n1)
. Folosind si inegalitatea ln n n 1,
2
obtinem ca Algoritmul Kruskal este mai eficient pentru grafuri sarace n
muchii, iar Algoritmul Prim este mai eficient pentru grafuri bogate n
muchii.
Observatia 2.4.3. Pentru implementarea Algoritmului Kruskal, memoram
graful ponderat conex (G, c), unde G = (V, E), V = {1, . . . , n}, E =
{e1 , . . . , em }, ntr-o matrice cu 3 linii si m coloane P = (pik ) i = 1, 3 avand
k = 1, m
semnificatia:
daca ek = [xk , yk ] E, atunci p1k = xk , p2k = yk si p3k = c(ek ).
Utilizam un vector S cu semnificatia
1, daca ek a fost selectata,
S[k] =
0, n caz contrar,
44
, n rest,
45
2.5
46
0, daca k = 0,
k
P
c() =
c(ei ), daca k 1
i=1
47
1
5
10
5
3
5
15
10
2
Figura 2.5.1:
Drumurile elementare de la nodul 1 la nodul 5 sunt 1 = (1, 3, 5), avand
costul c(1 ) = 10 + 5 = 15, 2 = (1, 4, 5), avand costul c(2 ) = 5 + 5 = 10,
deci 2 este un drum minim de la 1 la 5. Astfel distanta minima de la nodul
1 la nodul 5 este c(2 ) = 10.
Definitia 2.5.2. Fie (G, c) un graf ponderat, unde G = (V, E), V = {v1 , . . . ,
vn }, c : E R+ .
a) Matricea distantelor (costurilor) directe asociata grafului (G, c)
este matricea C = (cij )i,j=1,n definita prin
0, daca i = j,
min{c(e)|e = (vi , vj ) E}, daca i 6= j si (vi , vj ) E,
cij =
, daca i 6= j si 6 (vi , vj ) E
(pentru grafuri neorientate (vi , vj ) desemnand de fapt muchia [vi , vj ]).
c( ), = drum minim de la vi la vj ,
, n caz contrar.
Observatia 2.5.5. Evident, pentru orice graf neorientat atat matricea distantelor directe cat si matricea distantelor minime sunt matrice simetrice.
48
0 15 10 5 10
0 15 10 5
0
0
, C = 10 5 0 15 5 .
5
0
5
C=
10 10 20 0 5
10 0 5
5 5 15 10 0
5 5 0
tjk + cjk ik = min{tj + cji |vj {vi1 , . . . , vik1 }, vi V \ {vi1 , . . . , vik1 }}.
(2.5.1)
Se ia
tik = tjk + cjk ik
si se trece la pasul k + 1.
(2.5.2)
49
Teorema 2.5.1 (de corectitudine a Algoritmului Dijkstra). In contextul Algoritmului Dijkstra, avem
ti = csi , i {1, . . . , n}
(adica distanta ti calculata de algoritm este chiar distanta minima de la vs
la vi ).
Demonstratie. Vom demonstra prin inductie dupa k ca nodul vik selectat la
pasul k si distanta corespondenta tik calculata la acel pas verifica egalitatea
din enunt, adica
tik = csik ,
si, n plus, tik < .
Pentru k = 1 afirmatia este evidenta deoarece
vi1 = vs , ti1 = 0 = css .
Presupunem adevarata afirmatia pentru orice pas mai mic decat k si o
demonstram pentru pasul k. Fie vjk {vi1 , . . . , vik1 } un nod ce verifica egalitatea (2.5.1). Din descrierea algoritmului si din ipoteza de inductie (nodul
vjk fiind selectat la un pas anterior), rezulta ca tjk = csjk < si cjk ik < ,
deci tik < (conform (2.5.2)).
Daca (vs , . . . , vjk ) este un drum minim de la vs la vjk (exista, deoarece
csjk < ), atunci = (vs , . . . , vjk , vik ) este un drum de la vs la vik , avand
costul c() = csjk + cjk ik = tjk + cjk ik = tik (conform (2.5.2)), deci
csik tik < .
(2.5.3)
50
(2.5.4)
51
Distanta minima
0
5
10
10
15
52
DIJKSTRA(s) :
for i = 1, n do
// init
ializ
ari
S[i] 0; t[i] ; T AT A[i] ;
t[s] 0; T AT A[s] 0;
// s este nodul surs
a
repeat
// select
am urm
atorul nod x, ^
n ordinea cresc
atoare
// a distant
elor minime de la s la x
min ;
for i = 1, n do
if (S[i] = 0) and (t[i] < min) then
min t[i];
x i;
if (min < ) then
// exist
a x,
^l select
am
S[x] 1;
for i = 1, n do
// actualiz
am vectorii t s
i T AT A
if (S[i] = 0) and (cxi < ) then
if (t[i] > t[x] + cxi ) then
t[i] t[x] + cxi ;
T AT A[i] x;
while (min < );
Observatia 2.5.10. Implementarea anterioara necesita O (n2 ) operatii (deoarece blocul repeat se executa de cel mult n ori si necesita de fiecare data
cel mult n comparatii pentru determinarea nodului selectat x si cel mult n
comparatii si n adunari pentru actualizarea vectorilor t si T AT A). Aceasta
este de fapt si complexitatea Algoritmului Dijkstra (n implementarea optima) n cazul memorarii grafului prin matricea distantelor directe.
2.6
53
(2.6.1)
Figura 2.6.1:
Definitia 2.6.2. Fie R = (G, s, t, c) o retea, unde G = (V, E). Un flux
n reteaua R este o functie f : V V R ce verifica urmatoarele doua
proprietati:
X
jV
(2.6.2)
(2.6.3)
jV
54
Figura 2.6.2:
Lema 2.6.1. Fie R = (G, s, t, c) o retea, unde G = (V, E). Pentru orice flux
f n reteaua R are loc egalitatea
!
X
X
X
X
f (i, t)
f (t, i) =
f (i, s)
f (s, i) .
iV
iV
iV
iV
Definitia 2.6.3. Fie R = (G, s, t, c) o retea, unde G = (V, E). Pentru orice
flux f n reteaua R, numarul
!
X
X
X
X
v(f ) =
f (i, t)
f (t, i) =
f (i, s)
f (s, i)
iV
iV
iV
iV
55
56
57
Figura 2.6.3:
Definitia 2.6.10. Fie R = (G, s, t, c) o retea, unde G = (V, E). O sectiune
(t
aietur
a) n reteaua R este o pereche (S, T ) V V ce verific
a urmatoarele
proprietati:
S T = V, S T = ,
s S, t T.
Observatia 2.6.6. Daca (S, T ) este o sectiune n reteaua R = (G, s, t, c), unde
G = (V, E), atunci V = S T este o partitie a multimii V a nodurilor retelei
(adica V = S T , S 6= , T 6= , S T = ) a.. s S si t T . Rezulta
ca numarul de sectiuni ale retelei R este egal cu numarul de submultimi
S \ {s} V \ {s, t}, deci cu
2n2, unde n = card (V ).
Definitia 2.6.11. Fie R = (G, s, t, c) o retea, unde G = (V, E). Pentru
orice sectiune (S, T ) n reteaua R, numarul
XX
c(S, T ) =
c(i, j)
iS jT
58
Lema 2.6.3. Fie R = (G, s, t, c) o retea. Pentru orice flux f si orice sectiune
(S, T ) n reteaua R avem
v(f ) =
XX
iS jT
59
XX
iS jT
XX
iS jT
(c(i, j) 0) = c(S, T ),
0, n rest
60
Figura 2.6.4:
Conform rezultatelor de mai sus obtinem urmatorul algoritm pentru determinarea unui flux de valoare maxima ntr-o retea.
Algoritmul 2.6.1 (Ford-Fulkerson). Fie R = (G, s, t, c) o retea, unde G =
(V, E).
Conform Teoremei 2.6.1, schita algoritmului, descrisa n pseudocod, are
urmatoarea forma.
61
FORD FULKERSON :
f 0;
// sau f f0 , unde f0 este un flux
// disponibil init
ial
repeat
LANT
if (EXISTA
DE CRES
TERE) then
// exist
a lant
uri de cre
stere
// relativ la fluxul curent f
LANT
DE CRES
TERE;
// se determin
a
// un astfel de lant
de cre
stere
f f r(); // se m
are
ste valoarea fluxului curent,
// de-a lungul lant
ului de cre
stere
LANT
while (EXISTA
DE CRES
TERE);
// nu mai exist
a lant
uri de cre
stere,
// deci fluxul curent este de valoare maxim
a
AFIS
ARE(f );
// se afi
seaz
a fluxul de valoare maxim
a
In continuare detaliem implementarea acestui algoritm. Presupunem ca
V = {1, 2, . . . , n}, s = 1, t = n,
cu n 2.
Pentru depistarea si memorarea eventualelor lanturi de crestere relativ la
fluxul curent vom utiliza doi vectori SEL si T AT A avand semnificatia
1, daca exista un C-lant de la nodul s = 1 la nodul i,
SEL[i] =
0, n caz contrar,
T AT A[i] =predecesorul direct al nodului i pe C-lantul
de la nodul s = 1 la nodul i,
i {1, . . . , n}.
Algoritmul descris n pseudocod are urmatoarea forma (detaliata).
62
// se cite
ste ret
eaua dat
a
// fluxul init
ial
vmax 0;
// valoarea fluxul maxim
repeat // se caut
a lant
uri de cre
stere a fluxului curent,
// folosind Observat
ia 2.6.9
CALCUL REZIDUURI;
// se determin
a reziduul s
i
// graful rezidual ale ret
elei relativ la fluxul curent
SEL[1] 1;
// se selecteaz
a nodul surs
a
for i = 2, n do SEL[i] 0;
T AT A[1] 0;
// pt. memorarea C-lant
urilor
// ce pornesc din nodul surs
a
DF(1);
// se parcurge graful rezidual, memor^
and
// C-lant
urile ce pornesc din nodul surs
a;
// parcurgerea DF, poate fi
^nlocuit
a cu
// parcurgerea BF (Algoritmul Edmonds-Karp )
if (SEL[n] = 1) then
// s-a selectat nodul destinat
ie,
// deci exist
a lant
de cre
stere a fluxului
rmin ;
// reziduul minim, de-a lungul
// lant
ului de cre
stere
a lant
ul de cre
stere
DET LANT CR; // se determin
// a fluxului
si reziduul minim
// se m
are
ste fluxul curent, de-a
MARIRE FLUX;
// lungul lant
ului de cre
stere
vmax vmax + rmin;;
// se actualizeaz
a valoarea
// fluxului curent
while (SEL[n] = 1);
// nu mai exist
a lant
uri de cre
stere a fluxului,
// deci fluxul curent este maxim
AFIS
ARE REZULTATE;
// se afi
seaz
a fluxul maxim
si valoarea sa,
// eventual
si sect
iunea de capacitate minim
a,
// calculat
a conform (2.6.4) astfel:
// S = {i {1, . . . , n} | SEL[i] = 1},
// T = {i {1, . . . , n} | SEL[i] = 0}
Functiile utilizate sunt descrise n continuare.
63
CALCUL REZIDUURI :
for i = 1, n do
for j = 1, n do
if (fij < cij ) then
rij cij fij ;
else
if (fji > 0) then
rij fji ;
else
rij 0;
DF(i) :
for j = 1, n do
if (rij > 0 and SEL[j] = 0) then
T AT A[j] i; SEL[j] 1;;
DF(j);
// recursiv
DET LANT CR :
// se determin
a reziduul minim de-a
// lungul lant
ului de cre
stere, parcurs de la n c
atre 1
j n;
while (j 6= 1) do
i T AT A[j];
if (rmin > rij ) then rmin rij ;
j i;
MARIRE
FLUX :
// se m
are
ste fluxul de-a lungul
// lant
ului de cre
stere, parcurs de la n c
atre 1
j n;
while (j 6= 1) do
i T AT A[j];
if (cij > fij ) then
fij fij + rmin;
else
fji fji rmin;
j i;
Teorema 2.6.2 (de corectitudine a Algoritmului Ford-Fulkerson).
In contextul Algoritmului 2.6.1, fie R = (G, s, t, c) reteaua data, unde G =
(V, E). Presupunem ca toate capacitatile arcelor retelei sunt numere ntregi,
adica
c(i, j) N, (i, j) E.
64
unde
cmax = max{c(i, j) | (i, j) E}
(2.6.5)
65
si astfel obtinem
k (card (V ) 1)cmax v(f0 ),
deci numarul k de pasi ai algoritmului (numarul de lanturi de crestere succesive construite) este finit, adica exista k N astfel ncat reteaua R nu
mai contine lanturi de crestere relativ la fluxul fk . Conform Teoremei 2.6.1
rezulta ca fk este un flux de valoare maxima n R. Conform (2.6.5), toate
componentele fluxului fk si valoarea acestuia sunt numere ntregi.
Exemplul 2.6.10. Pentru reteaua R din Figura 2.6.1, aplicarea Algoritmului
Ford-Fulkerson este evidentiata n Figurile 2.6.5-2.6.10.
Figura 2.6.5:
Figura 2.6.6:
Figura 2.6.7:
Figura 2.6.8:
Figura 2.6.9:
66
67
Figura 2.6.10:
Lanturile succesive de crestere relativ la fluxul curent sunt evidentiate
prin ngrosare, si anume:
1
2
3
4
4
= [1, 2, 3, 5, 6],
= [1, 2, 3, 6],
= [1, 4, 3, 6],
= [1, 4, 5, 3, 6],
= [1, 4, 5, 6].
68
unde
Deci X
(f )
D, unde
(
D=
X R
j=1
nn
0 Xij Cij , i, j {1, . . . , n},
n
X
j=1
Xji
n
X
j=1
Xij = 0, i {2, . . . , n 1} .
69
n
X
i=1
Xin
n
X
Xni ,
i=1
avem v(f ) = F (X (f ) ).
Rezulta ca un flux f n R este un flux de valoare maxima n R daca si
numai daca matricea X (f ) este un punct de maxim al functiei F (pe domeniul
D). F este o functie reala de n2 variabile reale.
Cum F este o functie continua, iar multimea D este compacta (adica
nchisa si marginita), rezulta ca F este marginita si si atinge marginile, deci
exista un punct de maxim X al functiei F (pe domeniul D).
Xti
it
XRnn i=1
i=1
n
n
P
P
Xji
Xij = 0, i {1, . . . , n} \ {s, t};
j=1
j=1
0 Xij Cij , i, j {1, . . . , n}.
70
Totusi, prin impunerea unor modalitati judicioase de construire a lanturilor de crestere succesive n cadrul Algoritmului Ford-Fulkerson, se obtin algoritmi care rezolva problema fluxului maxim si n cazul capacitatilor irationale.
Prezentam n continuare un astfel de algoritm, bazat pe parcurgerea n latime
(BF) a grafului rezidual.
Algoritmul Edmonds-Karp este un algoritm ce rezolva problema determinarii unui flux de valoare maxima si problema determinarii unei sectiuni
de capacitate minima ntr-o retea arbitrara, cu capacitati numere reale,
prin cresterea succesiva a valorii fluxului curent de-a lungul unor lanturi
de crestere, la fel ca n Algoritmul Ford-Fulkerson.
Algoritmul 2.6.2 (Edmonds-Karp). Fie R = (G, s, t, c) o retea, unde G =
(V, E).
Algoritmul Edmonds-Karp are aceeasi forma ca si Algoritmul Ford-Fulkerson, aceasta forma comuna fiind descrisa detaliat n pseudocod n Algoritmul
2.6.1. Singura deosebire este ca la fiecare pas se construieste un lant de
crestere (relativ la fluxul curent) de lungime minim
a (binenteles, doar
daca mai exista lanturi de crestere).
71
, n caz contrar,
unde l() reprezinta lungimea lantului .
Lema 2.6.5. Fie f un flux n reteaua R = (G, s, t, c), unde G = (V, E). Fie
un lant de crestere de lungime minima n reteaua R relativ la fluxul f si
fie f = f r() fluxul obtinut prin marirea fluxului f de-a lungul lantului
de crestere . Atunci au loc urmatoarele inegalitati:
lf (s, i) lf (s, i), i V,
lf (i, t) lf (i, t), i V.
(2.6.6)
(2.6.7)
mn
,
2
Figura 2.6.11:
Figura 2.6.12:
Figura 2.6.13:
72
73
Figura 2.6.14:
Figura 2.6.15:
Lanturile succesive de crestere relativ la fluxul curent sunt evidentiate
prin ngrosare, si anume:
1
2
3
4
= [1, 2, 3, 6],
= [1, 4, 3, 6],
= [1, 4, 5, 6],
= [1, 4, 3, 5, 6].
74
Tema 3
Metoda Divide et Impera
3.1
76
dupa care, combinand rezultatele celor doua prelucrari, se obtine prelucrarea dorita a ntregii secvente (ap , . . . , aq ).
pentru secvente (ap , . . . , aq ), cu q p < , prelucrarea se poate face
direct, fara descompunere.
Algoritmul poate fi descris recursiv astfel:
DIVIMP(p, q, S) :
// Prelucrarea secvent
ei (ap , . . . , aq )
if q p < then
PRELUCREAZA(p, q, S); // Prelucrarea se face direct,
// rezult^
and solut
ia S a secvent
ei (ap , . . . , aq )
else
DESCOMPUNERE(p, q, m);
// Se descompune problema,
// adic
a se determin
a m
DIVIMP(p, m, S1);
// Se obt
ine solut
ia S1 pentru
// subsecvent
a (ap , . . . , am )
DIVIMP(m + 1, q, S2);
// Se obt
ine solut
ia S2 pentru
// subsecvent
a (am+1 , . . . , aq )
COMBINA(S1 , S2 , S);
// Se combin
a solut
iile S1 s
i S2 ,
// rezult^
and solut
ia S a secvent
ei (ap , . . . , aq )
Procedura trebuie apelata prin:
DIVIMP(1, n, S).
In acest algoritm:
reprezinta lungimea maxima a unei secvente (ap , . . . , aq ), notata prescurtat prin (p, q), pentru care prelucrarea se poate face direct, fara a
mai fi necesara mpartirea n subprobleme; procedura
PRELUCREAZA(p, q, S)
realizeaza prelucrarea secventelor de acest tip, furnizand rezultatul n
S.
Procedura
COMBINA(S1 , S2 , S)
realizeaza combinarea rezultatelor S1 , S2 ale prelucrarii celor doua subsecvente vecine (p, m) si (m + 1, q), obtinandu-se rezultatul S al prelucrarii secventei (p, q).
Valoarea m este obtinuta apeland procedura
DESCOMPUNERE(p, q, m).
3.2
77
Rezolvare. Vom nota o mutare cu perechea (i, j), ceea ce semnifica faptul ca
se muta un disc de pe tija i pe tija j (i, j {1, 2, 3}).
Daca n = 1, avem mutarea (1, 2).
Daca n = 2, avem mutarile (1, 3), (1, 2), (3, 2).
Daca n > 2, problema se complica.
Notam cu H(m, i, j) sirul mutarilor necesare pentru a muta primele m
discuri de pe tija i pe tija j, folosind pentru manevre cealalta tija k := 6ij.
(Avem i + j + k = 1 + 2 + 3 = 6.)
Rezulta ca, pentru problema noastra, avem de determinat sirul H(n, 1, 2).
Avem
(i, j),
daca m = 1,
H(m, i, j) =
H(m 1, i, k), (i, j), H(m 1, k, j), daca m 2.
78
79
Observatia 3.2.1. Algoritmul anterior este, sevident, un algoritm pecific metodei de programare Divide et Impera. Pentru evaluarea complexutatii
acestui algoritm, vom nota cu M(n) numarul de mutari afisate. Avem
M(n) =
=
1,
daca n = 1,
M(n 1) + 1 + M(n 1), daca n 2,
1,
daca n = 1,
2 M(n 1) + 1, daca n 2.
3.3
C
autarea binar
a
Problema c
aut
arii este urmatoarea:
Se considera un vector A = (a1 , a2 , ..., an ) si o valoare x. Se cere sa se
determine daca x se afla printre componentele vectorului A.
O cautare se poate ncheia
fie cu succes, caz n care se returneaza o pozitie n vector pe care se
afla valoarea cautata;
fie f
ar
a succes, caz n care se returneaza 1.
80
81
CAUTBIN(A, n, x) :
p 1; u n;
// (ap , . . . , au ) reprezint
a subsecvent
a curent
a
// la care se restr^
ange c
autarea
while p
u
do
p+u
;
m
2
if x = A[m] then
returneaz
a m;
else
if x < A[m] then
u m 1;
else
p m + 1;
returneaz
a 1;
Procedura trebuie apelata prin:
poz CAUTBIN(A, n, x).
Observatia 3.3.2. Pentru analiza algoritmului de cautare binara, presupunem
ca la fiecare iteratie avem o singura comparatie de chei, n urma careia se
poate decide ce relatie de ordine exista ntre valorile comparate.
Teorema 3.3.1 (complexitatea algoritmului de c
autare binar
a). Pentru algoritmul CAUTBIN, o cautare cu succes necesita cel mult k comparatii
de chei, iar o cautare fara succes necesita k 1 sau k comparatii de chei,
unde
k = [log2 n] + 1,
deci algoritmul are complexitatea O (log2 n).
Demonstratie. Pentru algoritmul de cautare binara ntr-un vector sortat cu
n componente, se poate asocia un arbore binar (de decizie) cu
n noduri interioare, etichetate cu numerele 1, 2, . . . , n reprezentate n
cercuri;
n+1 noduri terminale, etichetate cu numerele 0, 1, 2, . . . , n reprezentate
n patrate,
construit recursiv astfel:
a) daca n = 0, arborele este constituit din nodul 0 ;
b) altfel, daca n 1, atunci:
82
n+1
este nod r
ad
acin
a (nodul median este radacina);
2
subarborele st
ang este arborele
binar
corespunzator cautarii
n+1
binare ntr-un vector sortat cu
1 componente;
2
subarborele drept este arborele
h n i binar corespunzator cautarii
binare ntr-un vector sortat cu
componente, numerele nodu 2
n+1
.
rilor fiind crescute cu
2
83
(3.3.1)
84
Observatia 3.3.3. In cazul unei cautari fara succes, eticheta nodului terminal
n care se ajunge, poate determina pozitia pe care ar trebui inserata n vector
valoarea cautata, astfel ncat vectorul sa ramana n continuare sortat.
3.4
85
86
INTERCLAS(A, p, q, m) :
i p;
j m + 1;
k 1;
while (i m) and (j q) do
if A[i] A[j] then
B[k] A[i];
i i + 1;
else
B[k] A[j];
j j + 1;
k k + 1;
while i m do
B[k] A[i];
i i + 1;
k k + 1;
while j q do
B[k] A[j];
j j + 1;
k k + 1;
k 1;
for i = p, q do
A[i] B[k];
k k + 1;
Observatia 3.4.2. Chiar daca timpul de executie este de apreciat, se utilizeaza
un vector suplimentar de lucru, B.
Observatia 3.4.3. Complexitatea algoritmului este de ordinul O (n ln n).
Observatia 3.4.4. Se poate mbunatati procedura INTERCLAS, micsorand
numarul de deplasari.
T
inem seama de urmatoarele:
1) Daca primul ciclu se termina cand i > m, atunci elementele ramase n
secventa (A[j], ..., A[q]) nu vor mai fi copiate n vectorul B, pentru ca
apoi sa fie readuse n A, deoarece ele ocupa deja pozitiile corecte.
87
88
INTERCLAS2(A, p, q, m) :
i p;
j m + 1;
k 1;
while (i m) and (j q) do
if A[i] A[j] then
B[k] A[i];
i i + 1;
else
B[k] A[j];
j j + 1;
k k + 1;
if j q then
lim j 1;
else
lim q m + i 1;
for j = m, i, 1 do
A[q m + j] A[j];
k 1;
for i = p, lim do
A[i] B[k];
k k + 1;
3.5
Sortarea rapid
a (quicksort)
89
n care
A[i] A[k] A[j],
(3.5.1)
pentru orice i si j cu p i k 1 si k + 1 j u.
Se obtin, astfel, doua secvente mai mici (partitii)
(A[p], ..., A[k 1]) si (A[k + 1], ..., A[u]),
care pot fi prelucrate (sortate), n acelasi mod, independent una de alta.
Secventele de lungime 1 sau cele vide care rezulta n urma partitionarii nu
se mai prelucreaza.
Un element A[k], care satisface relatia (3.5.1), se numeste pivot. El are
proprietatea ca a ajuns deja pe pozitia finala, n viitorul vectorul sortat,
deoarece
toate elementele din secventa (A[p], ..., A[k 1]) sunt mai mici sau egale
cu el;
toate elementele din secventa (A[k+1], ..., A[u]) sunt mai mari sau egale
cu el.
In final, spre deosebire de algoritmul mergesort, n care la etapa de combinare se realiza interclasarea celor doua secvente sortate, aici aceasta etapa
este evitata deoarece, n urma prelucrarilor celor doua secvente, rezulta deja
toata secventa (A[p], ..., A[u]) sortata.
Exemplul 3.5.1.
Determinarea pivotului:
Se compara A[p], pe rand, cu A[u], A[u 1], ... s.a.m.d. pana cand se
ajunge la o pozitie u cu A[p] > A[u ]. Atunci se executa urmatoarele
operatii
A[p] A[u ]
pp+1
u u
90
A[p ] A[u]
p p
uu1
91
Analiza algoritmului:
Vom evalua numarul de comparatii (de chei), celelalte operatii nedepasind
ordinul de marime al acestora.
In procedura PIVOT se efectueaza u p comparatii (de chei).
Daca vectorul A este de la nceput sortat crescator, atunci procedura
PIVOT va fi apelata succesiv pentru perechile de indici
(1, n); (2, n); ...; (n 1, n),
ceea ce necesita
(n 1) + (n 2) + + 2 + 1 =
n(n 1)
comparatii.
2
92
// Se determin
a pozit
ia median
a
// a secvent
ei de sortat
med A[k];
// Se ret
ine elementul de pe pozit
ia median
a
min p;
max u;
repeat
while A[min] < med do
min min + 1
while A[max] > med do
max max 1
if min max then
A[min] A[max]
min min + 1;
max max 1;
while min max;
if p < max then
QUICKSORT2(A, p, max);
if u > min then
QUICKSORT2(A, min, u);
3.6
O problem
a de acoperire
93
Fiecare dintre cele patru suprafete este acum n conditiile problemei, deci
pentru fiecare suprafata se repeta procedeul de descompunere descris anterior.
94
Tema 4
Metoda program
arii dinamice
4.1
95
TEMA 4. METODA PROGRAMARII
DINAMICE
96
Deci este de preferat ca relatiile de recurenta sa fie rezolvate prin implementari nerecursive, utilizand strategia bottom-up, cu memorarea temporara
a solutiilor optime ale subproblemelor.
Prezentam o schema generala de lucru:
Problema data se descompune n subprobleme de acelasi tip, dar de
dimensiuni mai mici.
Se alege o structura de date n care se memoreaza solutiile optime ale
problemei si subproblemelor.
Se determina relatia de recurenta ce caracterizeaza solutia optima.
Se rezolva relatia de recurenta prin strategia bottom-up.
4.2
Subsir cresc
ator de lungime maxim
a
TEMA 4. METODA PROGRAMARII
DINAMICE
97
de lungime
construit astfel:
t1 = min {i | L[i] = k},
i=1,n
P [10] = 1;
P [9] = 1;
P [8] = 9;
P [7] = 8;
P [6] = 1;
P [5] = 8;
P [4] = 6;
P [3] = 5;
P [2] = 1;
P [1] = 2,
TEMA 4. METODA PROGRAMARII
DINAMICE
98
for j = 1, k do
afiseaz
a atj ;
4.3
Matricea drumurilor.
Warshall
Algoritmul Roy-
TEMA 4. METODA PROGRAMARII
DINAMICE
99
1 1
1 1
0 0
D=
1 1
1 1
0 0
1 1 1
1 1 1
D=
1 1 1
0 0 0
0 0 0
1
1
0
1
1
0
1
1
0
1
1
0
0
0
1
0
0
1
1 1
1 1
1 1
.
0 0
1 0
Observatia 4.3.1. Evident, orice graf neorientat are matricea drumurilor simetrica.
Observatia 4.3.2. Conform Observatiei 1.5.5, pentru i 6= j putem nlocui
termenul de drum cu drum elementar n definitia matricei drumurilor.
Urmatorul algoritm determina matricea drumurilor unui graf pornind de
la matricea de adiacenta.
Algoritmul 4.3.1 (Roy-Warshall). Fie G = (V, E) un graf simplu cu V =
{v1 , . . . , vn } si fie A = (aij )i,j=1,n matricea sa de adiacenta (avand toate
elementele 0 sau 1). Se calculeaza matricele
(k)
(k1)
dij
(4.3.1)
(k1) (k1)
dik dkj ,
k, i, j {1, . . . , n},
(4.3.2)
TEMA 4. METODA PROGRAMARII
DINAMICE
100
(k1)
dij = 1 dij
(k1)
= 1 sau dik
(k1)
= dkj
= 1 = (vi , . . . , vj ) drum cu
TEMA 4. METODA PROGRAMARII
DINAMICE
101
Observatia 4.3.3. Pentru n fixat, Algoritmul Roy-Warshall necesita 2n3 operatii (cate o operatie si pentru fiecare (k, i, j) {1, . . . , n} {1, . . . , n}
{1, . . . , n}), deci acest algoritm are complexitatea (n3 ).
Observatia 4.3.4. Algoritmul Roy-Warshall ramane evident valabil si pentru
grafuri nesimple, cu modificarea
1, daca aij > 0,
(0)
i, j {1, . . . , n}.
dij =
0, daca aij = 0,
Exemplul 4.3.2. Pentru graful din Exemplul 1.2.2, prin aplicarea Algoritmului Roy-Warshall obtinem matricele:
0 1 0 0 0
0 0 1 1 1
(0)
D =A=
1 1 0 0 0 (matricea de adiacenta);
0 0 0 0 0
0 0 0 1 0
(1)
0
0
1
0
0
1
0
1
0
0
0
1
0
0
0
0
1
0
0
1
(2)
(1)
1 1 1 1 1
1 1 1 1 1
D (3) =
1 1 1 1 1
0 0 0 0 0
0 0 0 1 0
(5)
1
1
1
0
0
1
1
1
0
0
1
1
1
0
0
1
1
1
0
1
0
1
0
0
0
(2)
; D =
(1) (1)
0
0
1
0
0
1
0
1
0
0
1
1
1
0
0
1
1
1
0
1
1
1
1
0
0
1 1 1 1 1
1 1 1 1 1
; D (4) = 1 1 1 1 1 ;
0 0 0 0 0
0 0 0 1 0
1
1
1
0
0
= D (matricea drumurilor).
TEMA 4. METODA PROGRAMARII
DINAMICE
102
(k)
(k1)
TEMA 4. METODA PROGRAMARII
DINAMICE
103
4.4
Vom expune un algoritm pentru determinarea distantelor minime si a drumurilor minime ntre orice doua noduri ale grafului ponderat dat. Acest
algoritm este asemanator cu Algoritmul Roy-Warshall pentru determinarea
matricei drumurilor.
Algoritmul 4.4.1 (Roy-Floyd). Fie (G, c) un graf ponderat, G = (V, E),
V = {v1 , v2 , . . . , vn }, c : E R+ . Fie C = (cij )i,j=1,n matricea distantelor
directe asociata grafului (G, c). Se calculeaza matricele
(k)
(k1) (k1)
min{cij , cik
(4.4.1)
+
(k1)
ckj },
k, i, j {1, . . . , n}.
(4.4.2)
Teorema 4.4.1 (de corectitudine a Algoritmului Roy-Floyd). In contextul Algoritmului Roy-Floyd, ultima matrice calculata este chiar matricea
distantelor minime asociata grafului (G, c), adica
C (n) = C .
TEMA 4. METODA PROGRAMARII
DINAMICE
104
, n caz contrar,
(k1)
cij = d cij
(k1)
= d cik
(k1)
+ ckj
(k1)
sau cik
(k1)
+ ckj
(k1)
= d < cij
TEMA 4. METODA PROGRAMARII
DINAMICE
105
0 15 10 5
0 15 10 5
0
0
(1)
(0)
; C = 5 0 5
5
0
5
C =C=
10 0 5
10 0 5
5 5 15 10 0
5 5 0
(deoarece, de exemplu,
0 15
0
C (2) =
5
10
5 5
0 15 10
0
C (4) =
5 0
10
5 5 15
(1)
(0)
(0)
(0)
0 15 10 5 15
10 5
0
(3)
;
5
0
5
0 5 ; C =
10 0 5
0 5
5 5 15 10 0
15 10 0
0 15 10 5 10
5 10
0
(5)
= C
10
5
0
15
5
5 ; C =
10 10 20 0 5
0 5
5 5 15 10 0
10 0
TEMA 4. METODA PROGRAMARII
DINAMICE
ROY FLOYD :
for i = 1, n do
for j = 1, n do
cij cij ;
106
// init
ializ
ari
for k = 1, n do
for i = 1, n do
for j = 1, n do
if (cik + ckj < cij ) then
cij cik + ckj ;
Considerand ca functia cost c este strict pozitiva, pentru determinarea
tuturor drumurilor minime (elementare) dintre doua noduri distincte x, y
putem utiliza echivalenta:
z 6= x,
(x, z, . . . , y) = drum minim
cxz + czy = cxy ,
unde multimea nodurilor este multimea standard V = {1, . . . , n}.
Astfel putem determina toate nodurile z ce sunt succesori directi ai nodului x pe drumuri minime de la x la y, si continuand acest procedeu pentru
subdrumurile minime dintre z si y se gasesc toate drumurile minime elementare de la x la y.
Tema 5
Metoda Backtracking
5.1
108
109
110
111
adica
Sk = {ak , ak + rk , ak + 2rk , . . . , bk }, k = 1, n.
Pentru acest caz particular, vom prezrnta n continuare sase variante pentru schema Backtracking: si anume doua variante iterative si patru variante
recursive.
Algoritmul 5.1.1 (Schema Backtracking iterativ
a, varianta 1).
BACKTRACKING :
k 1;
x[1] a[1] r[1];// preg
atim introducerea valorii init
iale a1
// pentru x1
while k > 0 do
if x[k] < b[k] then
// mai exist
a valori netestate pentru xk
x[k]
x[k]
+
r[k];
autare
// C
if (x[1], . . . , x[k]) verifica conditiile de continuare then
if k = n then
// (x[1], . . . , x[n]) este solut
ie rezultat
PRELUCREAZA(x[1],
. . . , x[n]);
(*)
// STOP, dac
a se dore
ste
// o singur
a solut
ie rezultat
else
k k + 1;
// Avansare
x[k] a[k] r[k];
// preg
atim introducerea
// valorii init
iale ak pentru xk
else
// nu mai exist
a valori netestate pentru xk
k k 1;
// Revenire
Urmatoarea schema este echivalenta cu cea de mai sus.
Algoritmul 5.1.2 (Schema Backtracking iterativ
a, varianta 2).
112
BACKTRACKING2 :
k 1;
x[1] a[1] r[1];// preg
atim introducerea valorii init
iale a1
// pentru x1
while k > 0 do
if k n then
if x[k] < b[k] then
// mai exist
a valori netestate pentru xk
x[k]
x[k]
+
r[k];
// C
autare
if (x[1], . . . , x[k]) verifica conditiile de continuare then
k k + 1;
// Avansare
x[k] a[k] r[k];
// preg
atim introducerea
// valorii init
iale ak pentru xk
else
k k 1;
// Revenire
else
PRELUCREAZA(x[1],
. . . , x[n]);
(*)
// STOP, dac
a se dore
ste
// o singur
a solut
ie rezultat
k k 1;
// Revenire, dac
a se doresc
// toate solut
iile rezultat
Observatia 5.1.10. Schemele Backtracking de mai sus genereaza toate solutiile
problemei date. Daca se doreste obtinerea unei singure solutii, atunci, n loc
de () se poate insera o comanda de oprire (STOP) sau, la unele probleme,
se poate forta revenirea.
Algoritmul 5.1.3 (Schema Backtracking recursiv
a, varianta 1).
113
BACKR1(k) :
// se genereaz
a (x[k], . . . , x[n])
x[k] a[k] r[k];// preg
atim introducerea valorii init
iale ak
// pentru xk
while x[k] < b[k] do
x[k]
// C
autare
x[k] + r[k];
if (x[1], . . . , x[k]) verifica conditiile de continuare then
if k = n then
// (x[1], . . . , x[n]) este solut
ie rezultat
PRELUCREAZA(x[1],
. . . , x[n]);
else
BACKR1(k + 1);
// Avansare, adic
a
// se genereaz
a, RECURSIV, (x[k + 1], . . . , x[n]).
// La ^
ncheierea apelului BACKR1(k + 1) se produce
// revinirea la funct
ia BACKR1(k)
Apelare: BACKR1(1).
Urmatoarea schema este echivalenta cu cea de mai sus.
Algoritmul 5.1.4 (Schema Backtracking recursiv
a, varianta 2).
BACKR2(k) :
if k n then
x[k] a[k] r[k];
while x[k] < b[k] do
x[k]
x[k] + r[k];
if (x[1], . . . , x[k]) verifica conditiile de continuare then
BACKR2(k + 1);
else
PRELUCREAZA(x[1],
. . . , x[n]);
Apelare: BACKR2(1).
Algoritmul 5.1.5 (Schema Backtracking recursiv
a, varianta 3).
114
BACKR3(k) :
for v = a[k], b[k], r[k] do
// C
autarea lui xk ^
n mult
imea Sk
x[k]
v;
if (x[1], . . . , x[k]) verifica conditiile de continuare then
if k = n then
// (x[1], . . . , x[n]) este solut
ie rezultat
PRELUCREAZA(x[1],
. . . , x[n]);
else
BACKR3(k + 1);
// Avansare, adic
a
// se genereaz
a, RECURSIV, (x[k + 1], . . . , x[n]).
// La ^
ncheierea apelului BACKR1(k + 1) se produce
// revinirea la funct
ia BACKR1(k)
Apelare: BACKR3(1).
Urmatoarea schema este echivalenta cu cea de mai sus.
Algoritmul 5.1.6 (Schema Backtracking recursiv
a, varianta 4).
BACKR4(k) :
if k n then
for v = a[k], b[k], r[k] do
x[k]
v;
if (x[1], . . . , x[k]) verifica conditiile de continuare then
BACKR4(k + 1);
else
PRELUCREAZA(x[1],
. . . , x[n]);
Apelare: BACKR4(1).
Observatia 5.1.11. Schemele Backtracking din Algoritmii 5.1.1, 5.1.2, 5.1.3 si
5.1.4 pot fi usor adaptate si pentru situati n care elementele fiecarei multimi
Sk nu sunt n progresie aritmetica.
Observatia 5.1.12. Daca n oricare din cele sase scheme de mai sus se renunta
la testul
[(x[1], x[2], . . . , x[k]) verifica conditiile de continuare],
considerandu-se astfel ca orice solutie partiala este valida (verifica conditiile
interne), atunci se vor obtine ca solutii ale problemei toate elementele produsului cartezian S1 S2 Sn .
5.2
115
1
2
3
4
5
1 2 3 4 5
ak = 1,
rk = 1, k = 1, n.
bk = n,
Conditiile interne:
116
j i 6= | xi xj |, 1 i < j n.
Conditiile de continuare:
Daca avem solutia partiala x = (x1 , . . . , xk1 ), atunci xk verific
a conditiile
de continuare daca
xk 6= xi si k i 6= | xk xi |, i = 1, k 1.
// fals
// adev
arat
5.3
117
Colorarea grafurilor
118
COLORARE(A, n, m) :
k 1;
x[1] 0;
while k > 0 do
if x[k] < m then
x[k] x[k] + 1;
if VALID(x, k) then
if k = n then
AFISARE(x);
else
k k + 1;
x[k] 0
;
else
k k 1;
VALID(x, k) :
for i = 1, k 1 do
if (aik 1 and x[i] = x[k]) then
returneaz
a 0;
returneaz
a 1;
119
2
1
1
5
3
5
Astfel problema colorarii unei harti se reduce la problema colorarii grafului asociat.
Observatia 5.3.1. Graful asociat unei harti este planar, adica exista o reprezentare grafica n plan a acestuia astfel ncat muchiile sa nu se intersecteze
decat n noduri.
Observatia 5.3.2. Celebritatea problemei colorarii hartilor a constat n faptul
ca n toate exemplele ntalnite, colorarea s-a putut face cu numai 4 culori,
dar teoretic se demonstrase ca sunt suficiente 5 culori.
Problema a aparut n 1852, cand un matematician amator, Fracis
Guthrie, a ncercat sa coloreze harta comitatelor britanice, folosind
numai 4 culori.
In anul 1976, Wolfgang Haken si Kenneth Appel, de la Universitatea
Illinois (SUA), au demonstrat ca pentru colorare sunt suficiente 4 culori.
Demonstratia problemei s-a efectuat cu ajutorul calculatorului electronic, analizandu-se 1482 configuratii n circa 1200 ore calculator.
Teorema 5.3.1 (Teorema celor 4 culori). Pentru colorarea unui graf
planar sunt suficiente patru culori.