Sunteți pe pagina 1din 25

V : este o mulime, finit i nevid, ale crei elemente se numesc noduri sau vrfuri; U : este o mulime de

perechi ordonate de elemente distincte din V, ale crei elemente se numesc arce.
Exemplu de graf orientat:
G=(V, U) unde:
V={ 1,2,3,4,5,6}
U={{1,5}, {2,1},{3,6},{4,1},{4,3},{5,2},{6,4},{6,5}}

Reprezentarea unui graf orientat admite dou forme i anume:


- reprezentare textual: aa cum s-a reprezentat graful din exemplul anterior;
- reprezentare grafic : arcele sunt reprezentate prin sgei orientate, iar nodurile
prin puncte.
n teoria grafurilor orientate se ntlnesc frecvent noiunile:
- extremitile unui arc: fiind dat arcul u=(x,y), se numesc extremiti ale sale
nodurile x i y;
x se numete extremitate iniial;
y se numete extremitate final.
- vrfuri adiacente: dac ntr-un graf exist arcul u=(x,y) (sau u=(y,x), sau
amndou), se spune despre nodurile x i y c sunt adiacente;
- inciden
dac ul i u2 sunt dou arce ale aceluiai graf, se numesc incidente dac au o extremitate
comun.
Exemplu. u1=(x,y) si u2=(y,z) sunt incidente;
dac u1=(x,y) este un arc ntr-un graf, se spune despre el si nodul x, sau nodul y, c sunt
incidente.
care intr n 4).
5. Graf complet. Graf turneu
Fie G=(V, U) un graf orientat. Graful G se numeste graf complet dac oricare dou vrfuri distincte ale sale sunt
adiacente. Dou vrfuri x si y sunt adiacente dac:
- ntre ele exist arcul (x,y), sau
- ntre ele exist arcul (y,x), sau
- ntre ele exist arcele (x,y) si (y,x).
Exemplu de graf orientat complet:
G=(V, U) unde: V={1,2,3,4}
U={(1,2),,(1,3), (1,4), (2,3), (2,4), (3,4)}
ntr-un graf complet cu n vrfuri, exist ntre n( n-1) /2 si n(n-1) arce

Lema Avem 3 n(n-1)/2 grafuri complete cu n noduri.


Un graf orientat este turneu, dac oricare ar fi 2 vrfuri i si j, ij, ntre ele exist un
singur arc: arcul(i,j) sau arcul (j,i)
Proprieti:
Orice graf turneu este graf complet.
Avem 2 n(n-1)/2 grafuri turneu cu n noduri
n orice graf turneu exist un drum elementar care trece prin toate vrfurile
grafului.
Problem. Fiind dat un graf turneu, se cere s se afiseze un drum elementar care trece
prin toate vrfurile.

#include<iostream.h>
int s[20],a[20][20],n,L,i,j;
void afisare_drum()
{int i; cout<<endl;
for(i=1;i<=n;i++)
cout<<s[i]<<" ";}
void generare_drum()
{int i,j,k,p,q;
if(a[1][2]==1)
{s[1]=1;
s[2]=2;}
else
{s[1]=2;
s[2]=1;}
L=2;
for(k=3;k<=n;k++)
{if(a[k][s[1]]==1)
p=1;
else
{i=1;
q=0;
while(i<L&&!q)
if(a[s[i]][k]==1&&a[k][s[i+1]]==1)
q=1;
else i++;
p=i+1;}
for(j=L;j>=p;j--)
s[j+1]=s[j];
s[p]=k;
L++;}
cout<<endl;}
int main()
{cout<<"n=";cin>>n;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
{cout<<"exista arcul ("<<i<<","<<j<<")?[1/0]";
do
{cin>>a[i][j];}
while(!(a[i][j]==0 || a[i][j]==1));
a[j][i]=1-a[i][j];}
generare_drum();
afisare_drum();
return 0;}

6. Lan
Fie G=(V, U) un graf orientat. Se numeste lan, n graful G, o succesiune de arce cu proprietatea c ori-care
dou arce consecutive au o extremitate comun (nu are importan orientarea arcelor).
Se ntlnesc noiunile:
extremitile lanului fiind dat lanul Lse numesc extremiti ale sale extremitatea arcului ui1 care nu
este comun cu arcul ui2 si extremitatea arcului uik care nu este comun cu arcul uik-1

lungimea lanului prin lungimea sa se nelege numrul de arce care apar n L;

7. Drum
Numim drum o succesiune de noduri care au proprietatea c oricare ar fi dou noduri succesive acestea sunt
legate printr-un arc. Un drum poate fi:
Elementar - un drum care conine doar noduri distincte. (fig 1)
Neelementar - un drum care nu conine doar noduri distincte. (fig 2)
Simplu - un drum care conine doar muchii distincte.
Compus - un drum care nu conine doar muchii distincte.

Fig. 1

Fig.2

8. Circuit
Numim circuit un drum n care toate arcele sunt distincte dou cte dou i exist un arc de la ultimul nod la
primul (numrul minin de noduri este 3). Un circuit poate fi:
Elementar - un circuit care conine doar noduri distincte (cu excepia primului i a ultimului, care
coincid). (fig. 1)
Neelementar - un circuit care nu conine doar noduri distincte (cu excepia primului i a ultimului, care
coincid). (fig. 2)

Fig.1
Fig. 2
Noiunea de lan/ciclu este valabil i n cazul grafurilor orientate (nu are importan sensul arcelor).
La drumuri/circuite toate arcele trebuie s aib aceeai orientare.

9.Grafurile n viaa de zi cu zi

Un exemplu de graf orientat este: reeaua de strzi a unui ora. Strzile sunt arcele n graf, iar interseciile
reprezint vrfurile grafului. ntruct mergnd pe jos ne putem deplasa pe orice strad n ambele sensuri, vom
spune c din punctul de vedere al pietonilor, graful unui ora este neorientat.
Cu totul altfel stau lucrurile n ceea ce privete conductorii auto, pentru c n orice ora exist strzi cu sens
unic. Pentru un ofer strzile trebuie s primeasc n graf o anumit orientare. Desigur c acele strzi pe care se
poate circula n ambele sensuri vor primi orientare dubl.
Alte exemple ar fi: circulaia sngelui n organism (sngele circul prin artere de la inim n corp, i prin vene
din corp spre inim), cunotinele (exist persoane pe care le cunoatem, dar ele nu ne cunosc pe noi, sau persoane
care ne cunosc, dar noi nu le cunoatem, sau persoane care ne cunosc i le cunoatem).
II.Reprezentare
Pentru a reprezenta un graf orientat, ntr-un program, exist mai multe modaliti folosind diverse structuri de
date; dintre acestea n continuare vom prezenta:
reprezentarea prin matricea de adiacen;
reprezentarea prin matricea vrfuri-arce;
reprezentarea prin matricea drumurilor;
reprezentarea prin listele de adiacen;
reprezentarea prin sirul arcelor.

1Matricea de adiacen

1.Matricea de adiacen este o matrice ptratic, de ordin n, si nu este neaprat simetric fa de


diagonala principal, aa cum este n cazul grafurilor neorientate.
Secvenele de citire a matricei de adiacen:
int a[100][100];
.................
cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{cout"a[ "<<i<<,<<j<<]=; cina[i][j];}
sau:
cout<<"n m ; cin>>n>>m;
for (i=1;i<=m;i++)
{cout"dati extremitatile arcului "<<i<<" ; cin>>x>>y;
a[x][y]=1;}
....................
2.Matricea de adiacen are toate elementele de pe diagonala principal egale cu 0 (ne referim la cazul
cnd graful nu are bucle).
3.Numrul elementelor egale cu 1 de pe linia i este egal cu gradul exterior al vrfului i.
int gr_ext(int i) //determinarea gradului exterior al unui nod i
{int j , s;
s=0;

for (j=1;j<=n;j++)
s=s+a[i][j];
return s;}
4.Numrul elementelor egale cu 1 de pe coloana i este egal cu gradul interior al vrfului i.
int gr int(int i) // determinarea gradului exterior al unui nod i
{int j, s;
s=0;
for (j=1;j<=n;j++)
s=s+a[j][i];
return s;}
5.Dac vrful i este un vrf izolat, pe linia i si coloana i nu sunt elemente egale cu 1.
int vf_izolat(int i)
{return (gr_ext(i)==0) && (gr_int(i)==0);
}
2.Matricea vrfuri-arce ( matricea de inciden)

1. Matricea vrfuri-arce nu este neaprat o matrice ptratic.


#Secvenele de citire a matricei vrfuri-arce:
int b[100][100];
.........................
cout<"n m ;
cin>>n>>m;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
{cout<<"b["<<i<<" ,<<j<<"]=";
cin>>b[i] [j];}
sau:
cout<<"n m ;
cin>>n>>m;
for (i=l;i<=m;i++)
{ cout<<"dati extremitatile arcului "<<i<<" "; cin>>x>>y;
b[x] [i]=1;
b[y][i]=-1;}
....................
2. Numrul elementelor egale cu l de pe linia i este egal cu gradul exterior al vrfului i:
int gr_ext_B( int i) //determinarea gradului exterior al unui nod i
{int j, nr;
nr=0;
for (j=1;j<=m;j++)
if (b[i][j]==1)
nr=nr+1;
return nr;}
3. Numrul elementelor egale cu -1 de pe linia i este egal cu gradul interior al vrfului i.

int gr_int_B( int i) //determinarea gradului interior al unui nod i


{int j, nr;
nr=0;
for (j=1;j<=m;j++)
if (b[i][j]==-1)
nr=nr+1;
return nr;}
4. Dac vrful i este un vrf izolat, pe linia i nu sunt elemente egale cu 1 sau -1.
int vf_izolat_B( int i) //funcia determin dac un nod este izolat
{return (gr_ext_B(i) ==0) && (gr_int_B(i)==0);}
5. Pe fiecare coloan j, exist un singur, element egal cu 1 i un singur element egal cu -1.
Indicele liniei pe care se af 1 este extremitatea iniial a arcului u;
Indicele liniei pe care se af -1 este extremitatea final a arcului u
Construirea matricei de adiacen, cnd se cunoaste matricea vfuri-arce.
- se parcurge matricea vrfuri-arce, de la prima pn la ultima coloan, cu j
- pe coloana j, se depisteaz indicele liniei pe care se af 1. fie acesta plus l;
- pe coloana j, se depisteaz indicele liniei pe care se af -I, fie acesta minus l;
- n matricea de adiacen elementul a[plus l, minus l] se face 1.
for (j=1 j<=m;j++)
{for (i=1;i<=n;i++)
if (b[i][j]==1) plusl=i;
else if (b[i][j]==-1) minusl=i;
a[plusl ][minusl]=1;}
Construirea matricei vrfuri-arce, cnd se cunoaste matricea de adiacen.
- se foloseste variabila ntreag k, cu urmtorul rol:
- reprezint numrul arcului la care s-a ajuns (la al ctelea element ai,j=1 s-a ajuns), care
este practic indicele
curent al coloanei la care s-a ajuns n matricea vrfuri-arce.
- k=0;
- se parcurge matricea de adiacen, linie cu linie
- dac se gseste un element ai,j=1, atunci
- se mrete k cu 1;
- in coloana k, din matricea vrfuri-arce, se trece
pe linia i valoarea 1
pe linia j valoarea -1
.......................
k=0;
for (i=1;i<=n;i++)
for (j=1 j<=n;j++)
if (a[i][j]==1)
{k=k+1;
a[i][k]=1;
a[j][k]=-l;}

3 Matricea drumurilor

1. Matricea drumurilor este o matrice ptratic.


n continuare, este prezentat n pseudocod algoritmul Roy-Warshall de determinare a
matricei drumurilorplecnd de la matricea de adiacen. Algoritmul const ntr-un ir de
transformri aplicate matricei de adiacen. Vom spune c exist drum de la nodul i la
nodul j, dac gsim un nod k cu proprietatea c exist drum de la i la k si drum de la k la
j. Astfel:
Un element ai,j care este 0 devine1, dac exist un nod k a.. ai,k=1 si ak,j=1. Pentru a
gsi toate arcele
nodului k trebuie parcurse pe rnd n variabila k toate nodurile 1,2,.., n.
...............
pentru k=1 ... n
pentru i=1 ... n (i#k)
pentru j = 1 ... n (j#k)
dac ai,j=0 si i!=k si j!=k atunci
ai,j= aik * akj
.....................
2. Dac n matricea drumurilor dii=1, nseamn c exist n graf un circuit de extremiti
i.
3. Dac n matricea drumurilor linia i si coloana i au elementele egale cu 0, nodul i este
un nod izolat.
*Programul /C++ de construire si afsare a matricei drumurilor.
#include <iostrearn.h>
int a[30][30], i, j, k, n, m, x, y;
int main()
{cout<<"n "; cin>>n;
cout<<"m="; cin>>m; // secvena de citire a matricei de adiacen
for (i=1;i<=m;i++)
{ cin>>x>>y; a[x] [y]=1 ;}
for (k=1;k<=n;k++) //secvena de transformare a matricei de adiacen n matricea drumurilor
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (a[i][j]==0)
a[i][j]=a[i][k] *a[k][j];
cout<<"matricea drumurilor este ";
for (i=1;i<=n;i++)
{for (j=1;j<=n;j++)
cout<<a[i] [j] " ";
cout<<endl;}
return 0;}

4.Lista de adiacen
Fie G=(V, U) un graf orientat, cu n vrfuri (V={ 1,2, ..., n}) si m arce.
Reprezentarea grafului G, prin liste de adiacen, const n:
- precizarea numrului de vrfuri n;
- pentru fiecare vrf i, se precizeaz lista L; a succesorilor si, adic lista nodurilor care
fac parte din
mulimea +(i).
Reprezentarea in calculator a unui graf se poate face utilizand listele de adiacenta a varfurilor, adic pentru
fiecare varf se alcatuiete lista vrfurilor adiacente cu el.
Fie graful din figura urmatoare:

Lista vecinilor varfului 5: 3, 4 (noduri adiacente) Pentru intreg graful vom avea mai multe liste :

Varful 1:
Varful 2 :
Varful 3 :
Varful 4 :
Varful 5 :
Varful 6
Ordinea varfurilor in cadrul unei liste nu este important. Pentru a genera o astfel de lista vom defini tipul nod :
struct nod {int nd;
nod *next;};
Toate listele se vor memora utiliznd un vector de liste :
nod *L[20];
Datele de intrare : numarul de varfuri si arcele se vor citi din fisier .O solutie de implementare este urmatoarea :
#include<iostream.h>
#include<fstream.h>
struct nod
{int nd;
nod *next;};
nod *L[20];
void afisare(int nr_nod) //afiseaza lista vecinilor varfuluii nr_nod
{nod *p=L[nr_nod];
if(p!=0)
{cout<<"lista vecinilor lui "<<nr_nod<<endl;
nod *c=p;
while(c)
{cout<<c->nd<<" ";
c=c->next;}
cout<<endl;}
}
int main()
{fstream f;int i,j,n;
nod *p,*q;
f>>n;
while(f>>i>>j)
{p=new nod; //se adauga j in lista vecinilor lui i
p->nd=j;
p->next=L[i];
L[i]=p;
}
f.close();
cout<<endl<<"listele de adiacente ";
for(i=1;i<=n;i++)
afisare(i);
}

Observatie : n exemplul anterior adugarea unui nou element n lista se face nainte celorlalte din lista
corespunzatoare.
Aceste dou moduri de reprezentare (prin matrice de adiacen i prin liste de vecini) se folosesc dupa natura
problemei. Adic, daca n problem se dorete un acces frecvent la arce, atunci se va folosi matricea de adiacen;
dac numrul de arce care se reprezint este mult mai mic dect nxn, este de preferat s se folosesc listele de
adiacen, pentru a se face economie de memorie.
Construirea matricei de adiacen, cnd se cunoaste L (listele vecinilor fiecrui nod).
..................
for (i=1;i<=n;i++)
{for (j=1;j<=nr_vec[i];j++)
a[i][L[i][j]]=1;}
..................

Construirea tabloului L (listele vecinilor nodurilor), cnd se cunoaste matricea de


adiacen
................
for (i=1; i<=n;i++)
{k=0;
for (j=1;j<=n;j++)
if (a[i][j]==1)
{k=k+1;
L[i][k]=j;}
}
................

5 irul arcelor
Fie G=(V, U) un graf orientat, cu n vrfuri (V={ 1,2, ..., n}) si m arce.
Reprezentarea grafului G const n precizarea numrului n de noduri i numrului m de
arce precum i n
precizarea extremitilor pentru fiecare arc n parte.:
Acest mod de reprezentare se implementeaz astfel:
1. Se d numrul n de noduri i numrul m de arce, iar extremitile fiecrui arc sunt trecute
n vectorii el i
e2, astfel:
- extremitile primului arc sunt el[1] i e2 [1];
- extremitile celui de-al doilea arc sunt e1[2] si e2[2];
- deci, U={( el[1],e2[1]) , (el[2],e2[2]) ,..., ( el [m],e2[m])}
Secvena C++corespunztoare este:

int el[100], e2[100];


int n, m, i;
cout<<"n="; cin>>n;
cout<<"m="; cin>>m;
for (i=1;i<=m;i++)
{cout<<"Dati extremitatile arcului cu numarul "<<i<<" ";
cin>>el[i]>>e2[i];}
..................

Construirea matricei de adiacen, cnd se cunoaste irul muchiilor ca mai sus.


...................
cout<<"n="; cin>>n;
for (i=1;i<=m;i++)
a[el[i]] [e2[i]]=1;
.................

Construirea irului arcelor, ca mai sus, cnd se d matricea de adiacen.

................
k=0;
for (i=1;i<=n;i++)
for (j==1;j<=n;j++)
if (a[i][j] ==1)
{ k=k+1;
e1[k]=i;

e2[k]=j;}
m=k;
.................

Construirea matricei de adiacen, cnd se cunoaste irul arcelor:


.....................
cout<<"n='"; cin>>n;
for (i=1;i<=m;i++)
a[u[i].x][u[i].y]=1;
......................

Construirea irului arcelor cnd se d matricea de adiacen:


...............
k=0;
for (i=1; i<=n; i++)
for (j=1;j<=n;j++)
if (a[i][j]==1)
{ k=k+1;
u[k].x=i;
u[k].y =j;}
m=k;
................

IV. Parcurgerea
Rezolvarea multor probleme de grafuri, presupune parcurgerea lor de la un anumit nod. Pentru explorarea
grafurilor, exist dou tipuri de algoritmi: de explorarea n lime i de explorare n adncime. Parcurgerea
grafurilor orientate este similar cu a grafurilor neorientate, se ine cont ns de orientare.
4.1 Explorarea grafurilor n lime
La explorarea n lime, dup vizitarea vrfului iniial, se exploreaz toate vrfurile adiacente lui, se trece apoi la
primul vrf adiacent i se exploreaz toate vrfurile adiacente acestuia i neparcurse nc, s.a.m.d.
Fiecare vrf se parcurge cel mult odat.
De exemplul pentru graful din figura de mai jos, se va proceda n felul urmtor: se pornete din nodul 1, (se
poate ncepe de la oricare alt nod)

se exploreaz n continuare vecinii acestuia : nodul 2 i apoi 4,

se obine 1,2,4
dupa care din 2 se exploreaz nodul adiacent acestuia 3. Nodul 1 nu se mai viziteaz odata

se obine 1,2,4,3
n continuare ar trebui parcuri vecinii lui 4 (1,2,4,3 ) dar acesta nu mai are vecini nevizitai i se trece la vecinii
lui 3 : 1,2,4,3 respectiv nodul 5 :

10

se obine 1, 2, 4, 3, 5
Vrful 6 rmne neparcurs .
Dac se parcurge graful ncepnd de la vrful 2, soluia este : 2,3,4,5, n timp ce parcurgerea ncepnd cu 4 va
reine doar vrful 4
Algoritmul
Se va folosi o coad n care se nscriu nodurile n form n care sunt parcurse: nodul iniial vrf (de la care se
pornete), apoi varfurilr a,b,..., adiacente lui vrf, apoi cele adiacente lui a, cele adiacente lui b,... ,.a.m.d.
Coad este folosit astfel:
- se ncrca primul vrf n coad;
- se afl toate vrfurile adiacente cu primul nod i se ntroduc dup primul vrf
- se ia urmtorul nod i i se afl nodurile adiacente
- procesul se repet pn cnd se ajunge la sfritul cozii
-Graful se va memora utiliznd matricea de adiacen a[10][10]
-pentru memorarea succesiunii vrfurilor parcurse se va folosi un vector c[20] care va funciona c o coad
-pentru a nu parcurge un vrf de dou ori se va folosi un vector boolean viz[20] care va reine :
- viz[k]=0 dac vrful k nu a fost vizitat nc
- viz[k]=1 dac vrful k a fost vizitat
-dou variabile : prim i ultim vor reine dou poziii din vectorul c i anume :
- prim este indicele componenei pentru care se parcurg vecinii (indexul
componentelor marcate cu rou n irurile parcurse anterior ). Prin urmare Varf=c[prim], este elementul pentru
care se determin vecinii (vrfurile adiacente)
-ultim este poziia n vector pe care se va face o noua inserare n vectorul c
(evident, de fiecare data cnd se realizeaz o noua inserare se mrete vectorul)
-vecinii unui vrf se caut pe linia acestui vrf : dac a[vrf][k]=1 nseamn c vrf i k sunt adiacente.
Pentru ca vrful k s fie adugat n coad trebuie c vrful s nu fi fost vizitat : viz[k]=0
#include<fstream.h>
#include<iostream.h>
int a[10][10],c[20],viz[10];
int n,m,prim,ultim,varf;
ifstream (date.in);
void bf_iterativ() //parcurgerea n lime
{int k;
while(prim<=ultim)
{varf=c[prim];
for(k=1;k<=n;k++)
if(a[varf][k]==1&&viz[k]==0) //l adaug pe k n coad dac este vecin pt. vrf i nu a fost vizitat
{ultim++;
c[ultim]=k;
viz[k]=1;}
prim++;
}
}
void main()
{clrscr();
int x,y;
f>>n>>m;
for(int i=1;i<=m;i++)
{f>>x>>y;
a[x][y]=1;
}
cout<<"matricea de adiac "<<endl; // afiare matrice de adiacenta
for( i=1;i<=n;i++)
{for(int j=1;j<=n;j++)

11

cout<<a[i][j]<<" ";
cout<<endl;
}
int nd;
prim=ultim=1;
cout<<"varful de inceput=";
cin>>nd; // varful de la care se porneste parcurgerea
viz[nd]=1;
c[prim]=nd;
bf_iterativ();
for(i=1;i<=ultim;i++) //afiarea cozii
cout<<c[i]<<" ";
return 0; }

Varianta recursiva de parcurgere se obine modificnd funcia de parcurgere iterativ adaugnd condiia necesar
autoapelului:
void bf_recursiv() //parcurgerea n lime
{int k;
if(prim<=ultim)
{varf=c[prim];
for(k=1;k<=n;k++)
if(a[varf][k]==1&&viz[k]==0) //l adaug pe k n coad dac este vecin pt. vrf i nu a fost vizitat
{ultim++;
c[ultim]=k;
viz[k]=1;}
prim++;
bf_recursiv();
}
}

Parcurgerea n laime a grafurilor memorate prin liste este similar cu diferena c vecinii unui nod adaugat n
coad se caut n lista corespunzatoare lui :
#include<iostream.h>
#include<fstream.h>
Ifstream (date.in);
struct nod
{int nd;
nod *next;};
nod *L[20];
int viz[100]; //marchez cu 1 nodurile vizitate
int m,n;
int prim,ultim,C[100];
void bfi_lis()
{int varf,nr;
nod *p;
while(prim<=ultim)
{varf=C[prim];
p=L[varf]; // se parcurge lista elementelor din varful cozii
while(p)
{nr=p->nd;
if(viz[nr]==0) //numai dac nu a fost vizitat
{ultim++; //mresc coada
C[ultim]=nr; //l adaug n coad
viz[nr]=1;}; //l marchez ca fiind vizitat
p=p->next;}
prim++; //avansez la urmtorul vrf din coad }
}
void afisare(int nr_nod)
{nod *p=L[nr_nod];
if(p==0)
cout<<nr_nod<<" este izolat "<<endl;
else
{cout<<"lista vecinilor lui "<<nr_nod<<endl;
nod *c=p;
while(c)

12

{cout<<c->nd<<" ";
c=c->next;}
cout<<endl;}
}
void main()
{fstream f;
int i,j;
nod *p,*q;
f>>n>>m;
while(f>>i>>j)
{p=new nod;
p->nd=j;
p->next=L[i];
L[i]=p;
}
f.close();
cout<<endl<<"listele de adiacen ";
for(i=1;i<=n;i++)
afisare(i);
int ndr;
cout<<endl<<"nodul de nceput ";
cin>>ndr;
viz[ndr]=1;
prim=ultim=1;
C[prim]=ndr;
cout<<endl<<"parcurgere n laime "<<endl;
bfi_lis();
for(i=1;i<=ultim;i++)
cout<<C[i]<<" ";
return 0;}
Funcia recursiv :
void bfr_lis()
{int varf,nr;
nod *p;
if(prim<=ultim)
{varf=C[prim];
p=L[varf];// se parcurge lista elementelor din vrful cozii
while(p)
{nr=p->nd;
if(viz[nr]==0)//numai daca nu a fost vizitat
{ultim++;//mresc coada
C[ultim]=nr;//l adaug n coad
viz[nr]=1;};//l marchez ca fiind vizitat
p=p->next;}
prim++; //avansez la urmtorul nod din coad
bfr_lis();
}
}

2. Parcurgerea grafurilor in adancime (depth first)


Parcurgerea unui graf n adncime se face prin utilizarea stivei (alocate implicit prin subprograme recursive).
Pentru fiecare vrf se parcurge primul dintre vecinii lui neparcuri nc
Dup vizitarea vrfului iniial x1, se exploreaz primul vrf adiacent lui, fie acesta x2 , se trece apoi la primul
vrf adiacent cu x2 i care nu a fost parcurs nc , s.a.m.d.
Fiecare vrf se parcurge cel mult odat
De exemplul pentru graful din figur de mai jos, se va proceda n felul urmtor: se pornete din vrful 1, (se
poate ncepe de la oricare alt vrf)

13

se exploreaz n continuare primul vecin al acestuia acestuia : vrful 2


se obine 1,2

dupa care din 2 se exploreaz vrful adiacent cu acesta i care nu a fost vizitat : 3.

se obtine 1,2,3
n continuare ar trebui s se parcurg vecinul lui 3 nevizitat : 4

se obine 1, 2, 3, 4
Pentru varful 4 ar trebui s se parcurg primul su vecin neparcurs (varful 1 dar acesta a fost deja parcurs. Nu
mai avem ce vizita i se trece la nivelul anterior din stiv, la vrful 3 :
1, 2, 3, 4 Se parcurge vecinul sau nevizitat, varful 5 .

Se obine : 1, 2, 3, 4 , 5.
Vrful 3 nu mai are vecini nevizitati i se trece pe nivelul anterior din stiv, vrful 2 : 1, 2, 3, 4 , 5. Nici acesta
nu mai are vecini nevizitati i se trece pe nivelul anterior la vrful 1 : 1, 2, 3, 4 , 5. Cum nici acesta nu mai are
vecini nevizitati se ncheie algoritmul. Vrful 6 rmne nevizitat.
Algoritmul
-Graful se va memora utiliznd matricea de adiacen a[10][10]
-pentru a nu parcurge un vrf de dou ori se va folosi un vector boolean viz care va reine :
- viz[k]=0 dac vrful k nu a fost vizitat nc
- viz[k]=1 dac vrful k a fost vizitat

14

-c i la parcurgerea n lime vecinii unui vrf se caut pe linia acestui vrf : dac a[nod][k]=1 nseamn c
vrfurile nod i k sunt adiacente. Pentru c vrful k s fie fie parcurs trebuie c vrful s nu fi fost vizitat :

viz[k]=0
#include<fstream.h>
#include<iostream.h>
int a[20][20],n,m,viz[100],gasit;
void dfmr(int nod)
{
cout<<nod<<" ";
viz[nod]=1;
for(int k=1;k<=n;k++)
if(a[nod][k]==1&&viz[k]==0)
dfmr(k);
}
void main()
{int x,y,j;
ifstream f(date.in);
f>>n>>m;
for(int i=1;i<=m;i++)
{f>>x>>y;
a[x][y]=1;}
cout<<endl<<"matricea de adiacente"<<endl;
for(i=1;i<=n;i++)
{for(j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl;}
cout<<endl<<"parcurgere in adancime incepand de la varful 1"<<endl;
dfmr(1);
return 0;}

V.Conexitate
Definiie. Fie G=(V, U) un graf orientat. Graful G se numete conex dac pentru oricare dou vrfuri x s i y, x
diferit y, exist un lant de extremiti x i y.
Fie G=(V, U) un graf orientat. Se numete component conex un graf orientat G1=(V1 ,U1) care verific
urmtoarele condiii:
este subgraf al grafului G;
este conex;
nu exist nici un lan n G care s lege un nod din V, cu un nod din V-V1.
Fie G=(V, U) un graf orientat. Graful G se numete tare conex, dac pentru oricare dou vrfuri x si y exist un
drum n G de la x la y si un drum de la y la x.

Algoritmul de descompunere a unui graf n componente tare conexe

15

Algoritmul procedeaz astfel:


- la nceput, nu este depistat nici o component tare conex ( nc=0);
- deci, nici un nod nu face parte din vreo component tare conex (luate=[ ]);
- se parcurg nodurile grafului, cu i;
- dac i nu a fost introdus n nici o component tare conex,
- se mreste numrul componentelor tare conexe cu 1,
- se construiete noua component tare conex, astfel:
- se intersecteaz predecesorii lui i cu succesorii si, i se reunesc cu {i}.
Pentru implementarea acestui algoritm, n limbajul C++, cu ajutorul programului prezentat mai jos, s-au folosit:
Funciile:
Succesori(i, S):care pune n irul S toate nodurile j, din graf , cu proprietatea c exist drum ntre i si ele.
Predecesori(i, P):care pune n irul P toate nodurile j, din graf, cu proprietatea c exist drum ntre ele si i.
Vectorul Comp ale crui componente, care sunt iruri de elemente, vor reine, la final, componentele tare conexe;
Variabilele:d : matricea drumurilor;
luate : un ir care reine toate nodurile care fac deja parte dintr-o component tare conex;
nc : reprezint numrul componentelor tare conexe depistate;
#include <iostream.h>
const p_inf=10000;
int sir[20];
int mat[20][20], c, nd,;
sir matmul[20][20], dr;
int i, k, j, n,m, ld,x,y,val;
void drum_de_la(int i,int j)
{ int k, gasitk,t;
if (i!= j)
{for (k=1;k<=n;k++)
{gasitk=0;
for (t=1;t<=nd[i][j]; t++)
if (d[i][j][t]==k) gasitk=1;
if (gasitk==1)
{ ld=ld+1;
dr[ld]=k;
drum_de_la(i,k);
ld=ld-1;}
}}
else{ for (k=ld;k>=1;k--) cout<<dr[k]<<" ";
cout<<endl;}
}
void afis()
{for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (c[i][j]==p_inf) cout<<"nu exista drum intre "<<i<<" si "<<j<<endl;
else if (i!=j)
{ cout<<"lung. drumului min de la "<<i<<" la "<<j<<" este "<<c[i][j]<<endl;
cout<<"iar drumurile sunt :"<<endl;
ld=1;
dr[ld]=j;
drum_de_la(i, j);}
}
void reuneste(sir x,int nx, sir y, int ny, sir z, int& nz)
{ int i, j, ok;
nz=0;
for (i=1;i<=nx;i++)
{nz++;
z[nz]=x[i];}
for (j=1;j<=ny;j++)
{ok=0;
for (i=1;i<=nx;i++)
if (x[i]==y[i]) ok=1;
if (!ok)
{nz++;
z[nz]=y[j];}}

16

}
void face_sirul(sir x, int nx, sir y, int& ny)
{int i;
ny=0;
for (i=1;i<=nx;i++)
{ny++;
y[ny]=x[i]; }
}
int main()
{ cout<<"n="; cin>>n;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (i==j)
c[i][j]=0;
else c[i][j]=p_inf;
cout<<"m="; cin>>m;
for (i=1;i<=m;i++)
{cout<<"x y val " ; cin>>x>>y>>val;
c[x][y]=val;}
for (i=1;i<=n;i++)
{for (j=1;j<=n;j++)
cout<<c[i][j]<<" ";
cout<<endl;}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if ((i!=j) && (c[i][j]<p_inf))
{ nd[i][j]=1;
d[i][j][1]=i;}
else nd[i][j]=0;
for (k=1;k<=n;k++)
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (c[i][j]==c[i][k]+c[k][j])
reuneste(d[i][j],nd[i][j],d[k][j],nd[k][j],d[i][j],nd[i][j]);
else if (c[i][j]>c[i][k]+c[k][j])
{ c[i][j]=c[i][k]+c[k][j];
face_sirul(d[k][j],nd[k][j],d[i][j],nd[i][j]);}
afis();
return 0;}

Algoritmul de determinare crei componente conexe i aparine un vrf


Pentru a determina componenta tare conex careia i aparine un vrf x se determin succesorii acestuia
(vrfurile la care se poate ajunge pornind de la vrful x) i n continuare se determin predecesorii
acestuia (vrfurile de la care pornind se ajunge la x). Se utilizeaz doi vectori : suc i prec pentru
predecesori i succesori n care se va ncrca x pentru nodurile parcurse. Pentru determinarea
succesorilor i predecesorilor se utilizeaz parcurgerea n adancime astfel nct un successor pentru un
vrf k se gsete pe linia k iar un predecessor pentru un vrf k se gsete pe coloana k.
Pentru graful din figura urmtoare dac se dorete determinarea componentei tare conexe creia i
aparine vrful 4 :

Cei doi vectori vor fi :


Vectorul suc :
4
4

4
17

Observaie : de la 4 pornind n adncime se pot parcurge toate vrfurile


Vectorul prec :
4
4
4
4
4
0

Intersecia celor doi vectori reprezint componenta tare conexa creia i aparine vrful 4.
Iat o modalitate de rezolvare :
#include<fstream.h>
#include<iostream.h>
int a[20][20],n,m,suc[100],prec[100],x;
void dfsuc(int nod)
{suc[nod]=x;
for(int k=1;k<=n;k++)
if(a[nod][k]==1&&suc[k]==0)
dfsuc(k);
}
void dfprec(int nod)
{ prec[nod]=x;
for(int k=1;k<=n;k++)
if(a[k][nod]==1&&prec[k]==0)
dfprec(k);
}
int main()
{int y,j;
fstream f(date.in);
f>>n>>m;
for(int i=1;i<=m;i++)
{f>>x>>y;
a[x][y]=1;}
cout<<endl<<"matricea de adiacente"<<endl;
for(i=1;i<=n;i++)
{for(j=1;j<=n;j++)
cout<<a[i][j]<<" ";
cout<<endl;}
cout<<"x=";cin>>x;
dfsuc(x);
cout<<endl<<"succesorii lui "<<x<<endl;
for(i=1;i<=n;i++)
if(suc[i]!=0)
cout<<i<<" ";
dfprec(x);
cout<<endl<<"Predecesorii lui "<<x<<endl;
for(i=1;i<=n;i++)
if(prec[i]!=0)
cout<<i<<" ";
cout<<endl<<"componenta tare conexa in care se gaseste "<<x<<" este "<<endl;
for(i=1;i<=n;i++)
if(prec[i]==suc[i]&&suc[i]!=0)
cout<<i<<" "
return 0;}

VI.Drumuri maxime i minime


Algoritmul lui Djakstra
Fie G=(V, E) un graf orientat, unde V are n elemente (n vrfuri) i E are m elemente (m arce). Se cunosc costurile
arcelor.
Matricea costurilor:
0
1
9

0
7
3

2
0

2
0

18

Ne propunem s determinm costul minim de la un vrf la toate celelalte vrfuri. Fie acesta vrful 1.
Vom utiliza 3 vectori : Vectorul d care va reine lungimea drumurilor de la 1 la celelalte vrfuri. (d[i]=lungime
drum de la 1 la i). Iniial d reine :
0

Vectorul s, numit vector caracteristic va reine 1 pentru nodurile selectate ca participante la drumul minim, altfel
s reine 0. Iniial va reine 1 doar pentru vrful de pornire , n cazul nostru vrful
1

Vectorul t , vector de tip tat care va indica drumurile gsite ntre vrful 1 i celelalte vrfuri astfel nct pentru
fiecare vrf se va retine precedentul (tatl). Pentru vrful de pornire, 1 n cazul nostru, se reine 0. Iniial t va
reine :
1

Algoritmul :
Se pornete de la vrful 1(r=1, unde r are valoare de rdcin) . Se marcheaz n s cu 1 : s[r]=1
Matricea costurilor:
0
1
9

0
7
3

2
0

2
0

n vectorul d se ncarc costurile de la r la fiecare dintre celelalte vrfuri


Vectorul d :
0

Vectorul s :
1
Vectorul t :
0

Pentru vrfurile rmase, deci de n-1 ori se execut secvena :


Se determin cel mai apropiat vrf de varful 1 din vectorul d (valoarea minim din d) :
0

Acesta este vrful 2 care se aduga la drum :


:

19

min=1, vf=2
se marcheaz n s :
Vectorul s :
1

n continuare se pune problema dac pentru nodurile neadugate nc nu s-ar putea realiza mbuntiri ale
lungimii drumurilor prin 2:
Adic pentru un vrf x daca d[x]>d[vf]+a[vf][x] atunci se realizeaz modificarea efectiv n d i se adaug vf ca
fiind predecessor (tata) pentru x:
if(d[x]>d[vf]+a[vf][x])
{ d[x]=d[vf]+a[vf][x];
t[x]=vf; }

Se pot mbunti drumurile de la 1 la 3 prin 2 i de la 1 la 4 prin 2. Vectorii devin :


Vectorul d :
0

Vectorul s :
1
Vectorul t :
0

Mai sunt de adugat vrfurile 3,4, 5. Acestea se pot aga de vrfurile adugate (selectate) fie 1 fie 2.
Se procedeaz la fel : se determin cel mai apropiat vrf : min =3 si vf=5
Vectorul d :
0

Se selecteaz n s : s[vf]=1:Vectorul s :

20

Dar nu se mai pot obine mbuntiri ale drumurilor de la 1 la vrfurile rmase (3 sau 4) care s treac prin 5
prin urmare vectorul t rmne acelai :
Vectorul t :
0

Am ajuns la urmatoarea situaie :

Mai sunt de adugat vrfurile 3 i 4. Vrfurile adugate sunt 1 ,2 i 5


Se caut n continuare cel mai apropiat vrf neselectat nc(pentru care n s valoarea este 0). Acesta este 4 :
Min=4, vf=4.
Se adaug la arbore i se obine :

Se poate realiza o imbuntaire a drumului de la 1 la 3 prin 4 i se adaug 4 ca printe pentru 3, iar


d[3]=d[4]+a[4][3]=4+2=6

Vectorii devin:
Vectorul d :
0

Vectorul s :

21

Vectorul t :
0

La sfrit se adaug varful 3:

Practic se obine arborele (un graf parial):


Vectorii devin :
Vectorul d :
0

Vectorul s :
1
Vectorul t :

Soluie de implementare :
#include<fstream.h>
#include<iostream.h>
const pinf=1000;
ifstream f(date.in);
int a[20][20],n,m;
int r;//varful de inceput
int s[100],int d[100],t[100];
void citire_cost()
{ int i,j,x,y,c;
f>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)
a[i][j]=0;
else
a[i][j]=pinf;
for(i=1;i<=m;i++)
{f>>x>>y>>c;
a[x][y]=c;}
}
void afisare_mat()
{cout<<endl<<"matricea costurilor"<<endl;

22

for(int i=1;i<=n;i++)
{for(int j=1;j<=n;j++)
if(a[i][j]==pinf)
cout<<"pinf ";
else
cout<<a[i][j]<<" ";
cout<<endl;}
}
void afiseaza_vector(int v[100])
{for(int i=1;i<=n;i++)
cout<<v[i]<<" ";
cout<<endl;}
void cauta_min(int &vf)//caut varful cel mai apropiat de r care nu a fost selectat inca
{int min=pinf;
for(int i=1;i<=n;i++)
if(s[i]==0)
if(d[i]<min)
{min=d[i];
vf=i;}
}
void imbunatatire_drum(int vf)//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el
{for(int i=1;i<=n;i++)
if(s[i]==0)
if(d[i]>d[vf]+a[vf][i])
{d[i]=d[vf]+a[vf][i];
t[i]=vf;//l adaug pe vrf ca posibil printe pentru i
}
}
void drum(int i)
{if(t[i])
drum(t[i]);
cout<<i<<" ";
}
int main()
{int vf,min;
citire_cost();
afisare_mat();
cout<<"nodul de inceput?";
cin>>r;
for(int i=1;i<=n;i++)
if(i!=r)
{d[i]=a[r][i];
if(a[r][i]!=pinf)
t[i]=r;
}
for(i=1;i<=n-1;i++)
{cauta_min(vf);//caut varful cel mai apropiat de r care nu a fost selectat inca
s[vf]=1; //il selectez ca fiind vizitat
imbunatatire_drum(vf);//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el
}
cout<<endl;
cout<<"vectorul drum: "<<endl;
afiseaza_vector(d);
cout<<"vectorul critic: "<<endl;
afiseaza_vector(s);
cout<<"vectorul de tati: "<<endl;
afiseaza_vector(t);
for(i=1;i<=n;i++)
if(i!=r)
if(t[i]!=0)//daca vectorul a fost adaugat la arbore
{cout<<"drumul de la "<<r<<" la "<<i<<" este :"<<endl;
drum(i);
cout<<endl<<"si are lungimea "<<d[i]<<endl<<endl;}
else
cout<<"nu exista drum de la "<<r<<" la "<<i<<endl;
return 0;

23

Aplicaie : S se determine drumul minim de la x la y cu maxim k noduri impare


#include<fstream.h>
#include<iostream.h>
ifstrem f(date.in)
const pinf=1000;
int a[20][20],n,m,k,r
int s[100],int d[100], int t[100],
void citire_cost()
{ int i,j,x,y,c;
f>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)
a[i][j]=0;
else
a[i][j]=pinf;
for(i=1;i<=m;i++)
{f>>x>>y>>c;
a[x][y]=c;}
}
void afisare_mat()
{cout<<endl<<"matricea costurilor"<<endl;
for(int i=1;i<=n;i++)
{for(int j=1;j<=n;j++)
if(a[i][j]==pinf)
cout<<"pinf ";
else
cout<<a[i][j]<<" ";
cout<<endl;}}
void afiseaza_vector(int v[100])
{for(int i=1;i<=n;i++)
cout<<v[i]<<" ";
cout<<endl;}
void cauta_min(int &vf
{int min=pinf;
for(int i=1;i<=n;i++)
if(s[i]==0)
if(d[i]<min)
{min=d[i];
vf=i;}
}
int verific(int i)
{if(t[i])
return i%2+verific(t[i]);
else
return 0;
}
void imbunatatire_drum(int vf)//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el
{for(int i=1;i<=n;i++)
if(s[i]==0)
if(d[i]>d[vf]+a[vf][i])
{int x;
x=t[i];
t[i]=vf;
int k1=verific(i)+r%2;
if(k1<=k)
d[i]=d[vf]+a[vf][i];
else
t[i]=x;
}
}
void drum(int i)
{if(t[i])
drum(t[i]);
cout<<i<<" ";

24

}
int main()
{ int vf,min;
citire_cost();
afisare_mat();
cout<<"nodul de inceput?";
cin>>r;
s[r]=1;
cout<<"k=";
cin>>k;
for(int i=1;i<=n;i++)
if(i!=r)
{d[i]=a[r][i];
if(a[r][i]!=pinf)
t[i]=r; }
for(i=1;i<=n-1;i++)
{cauta_min(vf); //caut varful cel mai apropiat de r care nu a fost selectat inca
s[vf]=1; //il selectez ca fiind vizitat
imbunatatire_drum(vf);//incerc sa imbunatatesc drumurile de la r la varfurile neselectate inca prin el
}
cout<<endl;
cout<<"vectorul drum: "<<endl;
afiseaza_vector(d);
cout<<"vectorul critic: "<<endl;
afiseaza_vector(s);
cout<<"vectorul de tati: "<<endl;
afiseaza_vector(t);
int y;
cout<<"vf final=";
cin>>y;
cout<<endl;
if(d[y]==pinf)
cout<<"nu exxista solutie";
else
cout<<"drumul minim cu maxim k vrfuri impare are valoarea "<<d[y];
cout<<endl;
drum(y);
return 0;}

25

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

  • RCP 5667 08.09.05
    RCP 5667 08.09.05
    Document6 pagini
    RCP 5667 08.09.05
    Georgiana Bachrouch
    Încă nu există evaluări
  • Functia de Conducere A Maduvei Spinarii
    Functia de Conducere A Maduvei Spinarii
    Document10 pagini
    Functia de Conducere A Maduvei Spinarii
    Geta Robu
    Încă nu există evaluări
  • MS 2
    MS 2
    Document5 pagini
    MS 2
    Georgiana Bachrouch
    Încă nu există evaluări
  • MS 2
    MS 2
    Document5 pagini
    MS 2
    Georgiana Bachrouch
    Încă nu există evaluări
  • MS 2
    MS 2
    Document5 pagini
    MS 2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Functia de Conducere A Maduvei Spinarii
    Functia de Conducere A Maduvei Spinarii
    Document10 pagini
    Functia de Conducere A Maduvei Spinarii
    Geta Robu
    Încă nu există evaluări
  • MS 2
    MS 2
    Document5 pagini
    MS 2
    Georgiana Bachrouch
    Încă nu există evaluări
  • MS 2
    MS 2
    Document5 pagini
    MS 2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Orientate2
    Grafuri Orientate2
    Document25 pagini
    Grafuri Orientate2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Functia de Conducere A Maduvei Spinarii
    Functia de Conducere A Maduvei Spinarii
    Document10 pagini
    Functia de Conducere A Maduvei Spinarii
    Geta Robu
    Încă nu există evaluări
  • Functia de Conducere A Maduvei Spinarii
    Functia de Conducere A Maduvei Spinarii
    Document10 pagini
    Functia de Conducere A Maduvei Spinarii
    Geta Robu
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Orientate2
    Grafuri Orientate2
    Document25 pagini
    Grafuri Orientate2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Orientate2
    Grafuri Orientate2
    Document25 pagini
    Grafuri Orientate2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Orientate2
    Grafuri Orientate2
    Document25 pagini
    Grafuri Orientate2
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări
  • Grafuri Neorientate
    Grafuri Neorientate
    Document39 pagini
    Grafuri Neorientate
    Georgiana Bachrouch
    Încă nu există evaluări