October 3, 2017
Cuprins
1 Concepte de bază ı̂n teoria grafurilor 2
2 Parcurgerea grafurilor 5
2.1 Parcurgerea ı̂n lăţime (Breadth First) . . . . . . . . . . . . . 5
2.2 Parcurgerea ı̂n adâncime (Depth First) . . . . . . . . . . . . . 8
3 Seminar 11
4 Anexe 15
4.1 Anexa 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.2 Anexa 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1
1 Concepte de bază ı̂n teoria grafurilor
Vom introduce şi exemplifica ı̂n continuare câteva noţiuni necesare ı̂n dez-
voltarea capitolelor următoare.
Definiţia 1.1. i) Se numeşte semigraf interior al unui nod xk mulţimea
arcelor
Ux−k = {(xj , xk ) | (xj , xk ) ∈ U }
care sunt incidente spre interior nodului xk .
ii) Se numeşte semigraf exterior al unui nod xk mulţimea arcelor
avem semigraful interior vârfului x2 dat de Ux−2 = {(x1 , x2 ), (x3 , x2 ), (x5 , x2 )},
iar semigraful exterior aceluiaşi vârf este Ux+2 = {(x2 , x3 )(x2 , x4 )(x2 , x6 )}.
Definiţia 1.2. Semigradul interior (exterior) al unui nod xk este numă-
rul arcelor care sunt incidente spre interior (exterior) nodului xk şi se notează
cu δ − +
xk (respectiv δ xk ). Gradul unui nod xk , notat cu δ xk este suma semi-
gradelor nodului xk , adică
δ xk = δ − +
xk + δ xk .
δ− − + +
xk = card Uxk şi δ xk = card Uxk ;
2
Exemplul 1.2. Pentru graful din exemplul 1.1 avem δ − +
x2 = 3, δ x2 = 2,
aşadar gradul vârfului x2 este δ xk = 5. Graful nu are vârfuri izolate sau
suspendate.
Definiţia 1.3. Într-un graf G, prin drum vom ı̂ntelege o mulţime ordonată
de noduri ale grafului
cu proprietatea că există ı̂n graf toate arcele de forma (xi , xi+1 ), unde i =
1, ..., k − 1. Lungimea unui drum, notată l(d(x1 , xk )), este numărul
arcelor care ı̂l formează.
Un drum elementar este un drum ı̂n care fiecare nod apare o singură
dată. Un drum simplu este un drum ı̂n care fiecare arc apare o singură
dată, altfel se numeşte drum compus.
p(xi ) = δ +
xi .
Definiţia 1.6. Vom numi circuit un drum ı̂n care nodul iniţial coincide cu
cel final.
Un circuit elementar este un drum ı̂n care fiecare nod apare o singură
dată, cu excepţia celui final, care coincide cu cel iniţial.
Un circuit simplu este un circuit ı̂n care fiecare arc apare o singură
dată, iar un circuit hamiltonian este un circuit care trece prin toate
nodurile grafului.
Definiţia 1.7. Prin lanţ ı̂nţelegem un drum ı̂n care arcele nu au neapărat
acelaşi sens de parcurgere. Un ciclu este un circuit ı̂n care arcele nu au
neapărat acelaşi sens de parcurgere. (Aceste noţiuni sunt utilizate pentru
grafurile neorientate)
3
Prin analogie cu proprietăţile circuitelor vom numi ciclu elementar un
ciclu ı̂n care fiecare nod apare o singură dată, cu excepţia celui final, care
coincide cu cel iniţial, iar un ciclu simplu un ciclu ı̂n care fiecare arc apare
o singură dată.
Observaţia 1.3. Într-un graf neorientat noţiunile de drum şi lanţ sunt
echivalente şi de asemenea cele de circuit şi ciclu.
X = {x1 , x2 , x3 , x4 }
U = {(x1 , x2 ), (x1 , x4 ), (x2 , x3 ), (x3 , x4 ), (x4 , x1 )}
X 00 = {x1 , x3 , x4 }
U 00 = {(x1 , x4 ), (x3 , x4 ), (x4 , x1 )}.
Definiţia 1.9. Un graf simplu conex este un graf neorientat ı̂n care ı̂ntre
oricare două noduri există cel puţin un lanţ.
Un graf orientat G = (X, U ) se numeşte semitare conex dacă ı̂ntre
oricare două vârfuri ale sale există cel puţin un drum.
Un graf orientat G = (X, U ) se numeşte tare conex dacă pentru oricare
două vârfuri xi şi xj există cel puţin un drum de la xi la xj şi cel puţin un
drum de la xj la xi .
Observaţia 1.4. Pentru grafuri neorientate noţiunile de tare conex şi sim-
plu conex sunt echivalente, graful numindu-se doar conex.
4
Observaţia 1.5. Graful reprezentat geometric ı̂n figura 1 are două compo-
nente conexe.
Figura 1:
2 Parcurgerea grafurilor
Modalitatea de vizitare a tuturor vârfurilor grafului ı̂n care fiecare dintre
acestea este vizitat o singură dată se numeşte parcurgere sau traversare.
În acest capitol sunt prezentate metodele de parcurgere ı̂n lăţime (Breadth
First) şi ı̂n adâncime (Depth First).
Aceste metode de parcurgere sunt aplicate grafurilor neorientate şi pre-
supun selectarea unui vârf iniţial x1 şi identificarea acelor vârfuri xk ale
grafului cu proprietatea că există cel puţin un drum de la vârful iniţial către
xk . Grafurile cu proprietatea că oricare două vârfuri sunt conectate printr-
un drum se numesc grafuri conexe (vezi definiţia 1.9). Dacă graful este
tare conex, atunci prin aplicarea metodelor de parcurgere vor fi identificate
toate vârfurile grafului. Cele două modalităţi de parcurgere sunt prezentate
ı̂n continuare ı̂n cazul grafurilor neorientate, extinderea la grafuri orientate
fiind imediată.
5
mai departe până când au fost vizitate toate vârfurile conectate cu vârful
iniţial.
Astfel, ı̂n cadrul traversării BF, vârfurile grafului vor fi prelucrate ı̂n
ordinea crescătoare a distanţelor faţă de vârful iniţial, unde prin distanţa de
la xi la xj , notată δ(xi , xj ), vom considera ı̂n continuare numărul de muchii
ale unui cel mai scurt drum de la xi la xj .
Fie G = (X, U ) un graf cu n noduri. O variantă de implementare a
metodei BF este construită prin utilizarea următoarelor structuri de date:
• matricea A de adiacenţă a grafului (din care reiese care sunt vecinii
unui nod xi , i = 1, n);
• o structură de tip coadă, notată cu C, ı̂n care sunt introduse
vârfurile ce urmează a fi vizitate şi procesate (ı̂n sensul cercetării vecinilor
lor); (o coadă este o structură dinamică (un şir a cărui dimensiune este
variabilă) de tip FIFO - first in, first out, elementele părăsesc coada ı̂n
ordinea intrării lor ı̂n coadă, ca o coadă la pâine)
• un vector c cu n componente, unde n reprezintă numărul vârfurilor
grafului, (care ne va spune daca un nod a fost vizitat deja), unde
(
1, dacă nodul xi a fost adăugat ı̂n coadă;
ci =
0, altfel.
6
Exemplul 2.1. Fie graful reprezentat geometric atfel:
Figura 2:
c
t C
t x1 x2 x3 x4 x5 x6 x7 x8
1 x1
1 1 0 0 0 0 0 0 0
2 x2 x3 x4 x7
2 1 1 1 1 0 0 1 0
3 x3 x4 x7 x5
3 1 1 1 1 1 0 1 0
4 x4 x7 x5 x6
4 1 1 1 1 1 1 1 0
5 x7 x5 x6
5 1 1 1 1 1 1 1 0
6 x5 x6
6 1 1 1 1 1 1 1 0
7 x6 x8
7 1 1 1 1 1 1 1 1
8 x8
8 1 1 1 1 1 1 1 1
9
9 1 1 1 1 1 1 1 1
7
2.2 Parcurgerea ı̂n adâncime (Depth First)
Constă ı̂n a vizita vârful iniţial x1 şi a continua cu unul dintre vecinii săi
nevizitaţi xi . Tot timpul mergem ı̂n adâncime, cât este posibil, altfel ne
ı̂ntoarcem şi plecăm, dacă este posibil, spre un alt vecin nevizitat ı̂ncă.
Implementarea acestei metode poate fi realizată ı̂n mai multe moduri,
pentru menţinerea mulţimii vârfurilor vizitate până la momentul curent fi-
ind utilizată o structură de date S de tip stivă. (O stivă este o structură
dinamică (un şir a cărui dimensiune este variabilă) de tip LIFO - last in,
first out, elementele părăsesc stiva ı̂n ordinea inversă intrării lor ı̂n stivă, ca
o stivă de farfurii.)
Este evident că nici ı̂n cazul acestei variante nu vor fi vizitate vârfurile
care nu sunt conectate cu vârful iniţial ales.
8
Exemplul 2.2. Pentru graful din figura 2, prin aplicarea metodei descrise,
rezultă următoarea evoluţie:
t S
1 x1
2 x1 x2
3 x1 x2 x5
4 x1 x2 x5 x4
5 x1 x2 x5 x4 x3
6 x1 x2 x5 x4 x3 x6
7 x1 x2 x5 x4 x3 x6 x7
8 x1 x2 x5 x4 x3 x6
9 x1 x2 x5 x4 x3 x6 x8
10 x1 x2 x5 x4 x3 x6
11 x1 x2 x5 x4 x3
12 x1 x2 x5 x4
13 x1 x2 x5
14 x1 x2
15 x1
16
- a vectorului c:
9
c
t x1 x2 x3 x4 x5 x6 x7 x8
1 1 0 0 0 0 0 0 0
2 1 1 0 0 0 0 0 0
3 1 1 0 1 1 0 0 0
4 1 1 1 1 1 0 0 0
5 1 1 1 1 1 1 0 0
6 1 1 1 1 1 1 1 0
7 1 1 1 1 1 1 1 1
8 1 1 1 1 1 1 1 1
9 1 1 1 1 1 1 1 1
10 1 1 1 1 1 1 1 1
11 1 1 1 1 1 1 1 1
12 1 1 1 1 1 1 1 1
13 1 1 1 1 1 1 1 1
14 1 1 1 1 1 1 1 1
15 1 1 1 1 1 1 1 1
16 1 1 1 1 1 1 1 1
10
3 Seminar
1. Să se parcurgă prin ambele metode prezentate următoarele grafuri, scriind
evoluţia acestor parcurgeri:
i)
ii)
Soluţie:
i) În lăţime:
11
c
t C
t x1 x2 x3 x4 x5 x6 x7
1 x1
1 1 0 0 0 0 0 0
2 x2 x3 x4
2 1 1 1 1 0 0 0
3 x3 x4 x5
3 1 1 1 1 1 0 0
4 x4 x5 x6
4 1 1 1 1 1 1 0
5 x5 x6 x7
5 1 1 1 1 1 1 1
6 x6 x7
6 1 1 1 1 1 1 1
7 x7
7 1 1 1 1 1 1 1
8
8 1 1 1 1 1 1 1
12
În adı̂ncime:
t S
1 x1
2 x1 x2
3 x1 x2 x5
4 x1 x2 x5 x4
5 x1 x2 x5 x4 x3
6 x1 x2 x5 x4 x3 x6
7 x1 x2 x5 x4 x3 x6 x7
8 x1 x2 x5 x4 x3 x6
9 x1 x2 x5 x4 x3
10 x1 x2 x5 x4
11 x1 x2 x5
12 x1 x2
13 x1
14
t c
t x1 x2 x3 x4 x5 x6 x7
1 1 0 0 0 0 0 0
2 1 1 0 0 0 0 0
3 1 1 0 0 1 0 0
4 1 1 0 1 1 0 0
5 1 1 1 1 1 0 0
6 1 1 1 1 1 1 0
7 1 1 1 1 1 1 1
8 1 1 1 1 1 1 1
9 1 1 1 1 1 1 1
10 1 1 1 1 1 1 1
11 1 1 1 1 1 1 1
12 1 1 1 1 1 1 1
13 1 1 1 1 1 1 1
14 1 1 1 1 1 1 1
Aşadar ordinea ı̂n care sunt vizitate vârfurile corespunzător acestei vari-
ante este x1 , x2 , x5 , x4 , x3 , x6 , x7 .
13
ii) În lăţime:
c
t C
t x1 x2 x3 x4 x5 x6 x7
1 x1
1 1 0 0 0 0 0 0
2 x2 x3 x5 x7
2 1 1 1 1 0 0 0
3 x3 x5 x7 x4
3 1 1 1 1 1 0 0
4 x5 x7 x4 x6
4 1 1 1 1 1 1 0
5 x7 x4 x6
5 1 1 1 1 1 1 1
6 x4 x6
6 1 1 1 1 1 1 1
7 x4
7 1 1 1 1 1 1 1
8
8 1 1 1 1 1 1 1
În adı̂ncime:
t S
1 x1
2 x1 x2
3 x1 x2 x4
4 x1 x2 x4 x5
5 x1 x2 x4
6 x1 x2 x4 x3
7 x1 x2 x4 x3 x6
8 x1 x2 x4 x3 x6 x7
9 x1 x2 x4 x3 x6
10 x1 x2 x4 x3
11 x1 x2 x4
12 x1 x2
13 x1
14
14
t c
t x1 x2 x3 x4 x5 x6 x7
1 1 0 0 0 0 0 0
2 1 1 0 0 0 0 0
3 1 1 0 1 0 0 0
4 1 1 0 1 1 0 0
5 1 1 0 1 1 0 0
6 1 1 1 1 1 0 0
7 1 1 1 1 1 1 0
8 1 1 1 1 1 1 1
9 1 1 1 1 1 1 1
10 1 1 1 1 1 1 1
11 1 1 1 1 1 1 1
12 1 1 1 1 1 1 1
13 1 1 1 1 1 1 1
14 1 1 1 1 1 1 1
Aşadar ordinea ı̂n care sunt vizitate vârfurile corespunzător acestei vari-
ante este x1 , x2 , x4 , x5 , x3 , x6 , x7 .
15
4 Anexe
4.1 Anexa 1
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
typedef struct nn
{ int inf;
struct nn *leg;
} nod,* pnod;
16
else return 0;}
void breadth first(int v0,int a[10][10],int n)
{
pnod head=NULL;
pnod tail=NULL;
int c[10];
for(int i=0;i<n;c[i++]=0);
int r=insereaza coada(&head,&tail,v0);
c[v0]=1;
while(head){
r=extrage coada(&head,&tail,&i);
printf(’’\n%i’’,i+1);
for(int k=0;k<n;k++)
if((a[i][k]==1)&&(c[k]==0)){
r=insereaza coada(&head,&tail,k);
c[k]=1;
}
}
}
void main()
{
int n,v0,a[10][10];
clrscr();
printf(’’Numarul de varfuri:’’);
scanf(’’%i’’,&n);
printf(’’\nMatricea de adiacenta\n’’);
for(int i=0;i<n;i++)
for(int j=0;j<i;j++){
scanf(’’%i’’,&v0);
a[j][i]=a[i][j]=v0;
}
for(i=0;i<n;i++)a[i][i]=0;
printf(’’\nVarful initial ’’);
scanf(’’%i’’,&v0);
printf(’’\nParcurgerea BF a grafului este’’);
breadth first(v0,a,n);
}
17
4.2 Anexa 2
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
typedef struct nn{
int inf;
struct nn *leg;
}nod,* pnod;
else return 0;
}
int extrage stiva(pnod *head,int *info)
{
if(head){
pnod aux=*head;
*info=(*head)->inf;
(*head)=(*head)->leg;
free(aux);
return 1;
}
else return 0;}
18
for(int i=0;i<n;c[i++]=0);
int r=insereaza stiva(&head,v0);
c[v0]=1;
printf(’’\n%i’’,v0+1);
while(head){
r=extrage stiva(&head,&i);
for(int k=0;k<n;k++)
if((a[i][k]==1)&&(c[k]==0)){
r=insereaza stiva(&head,k);
c[k]=1;printf(’’\n%i’’,k+1);
}
}
}
void main()
{
int n,v0,a[10][10];
clrscr();
printf(’’Numarul de varfuri:’’);scanf(’’%i’’,&n);
printf(’’\nMatricea de adiacenta\n’’);
for(int i=0;i<n;i++)
for(int j=0;j<i;j++){
scanf(’’%i’’,&v0); a[j][i]=a[i][j]=v0;
}
for(i=0;i<n;i++)a[i][i]=0;
printf(’’\nVarful initial ’’);scanf(’’%i’’,&v0);
printf(’’\nParcurgerea DF a grafului este’’);
depth first(v0,a,n);
}
References
[1] I. Roşca, Gh. (coord.), Programarea calculatoarelor. Algoritmi ı̂n progra-
mare, Ed. ASE, Bucureşti, 2007.
19