Documente Academic
Documente Profesional
Documente Cultură
Grafuri
Grafuri
Nodurile grafului sunt interseciile. Relaia care se stabilete ntre nodurile grafului este:
nodul x este n relaie cu nodul y, dac exist trafic care leag direct intersecia asociat
nodului x cu intersecia asociat nodului y (se poate circula de la nodul x la nodul y).
Relaia nu are proprietatea de simetrie deoarece, dac exist o strad care leag direct
intersecia asociata nodului x cu intersecia asociat nodului y i pe aceast strad exist
trafic de la nodul x la nodul y, nu este obligatoriu ca pe acea strad s existe trafic i de la
nodul y la nodul x. Pentru reprezentarea traficului auto dintre intersecii se va folosi un
graf orientat.
Enunul problemei 3. La nivelul unui grup de persoane se face un studiu social. ntre
persoane se stabilesc relaii de prietenie, dar i relaii de simpatie. S se descrie cu
ajutorul grafului relaiile intre persoane.
Nodurile grafului sunt membrii grupului de persoane. ntre persoane se pot stabili
relaiile:
-Relaia de prietenie este o relaie definit astfel: persoana x este n relaie cu persoana y,
dac este prieten cu ea. Relaia este simetric deoarece, dac persoana x este prieten cu
persoana y, atunci i persoana y este prieten cu persoana x (relaia de prietenie
presupune reciprocitate). Pentru reprezentarea relaiilor de prietenie dintre membrii
grupului se va folosi un graf neorientat.
-Relaia de simpatie este o relaie definit astfel: persoana x este n relaie cu persoana y,
dac o simpatizeaz. Relaia nu este simetric deoarece, dac persoana x simpatizeaz
persoana y, nu este obligatoriu ca persoana y s simpatizeze persoana x (relaia de
simpatie nu presupune reciprocitate). Pentru reprezentarea relaiilor de simpatie dintre
membrii grupului se va folosi un graf orientat.
I.1.1. Graful neorientat
Elementele mulimii U (perechile de noduri) se numesc muchii. Mulimea U se mai
numete i mulimea muchiilor grafului G. O muchie, fiind un element din mulimea U,
este determinat de o submulime cu dou elemente din mulimea X: muchia k a grafului
(uk), care unete nodurile xi i xj, este determinat de submulimea {xi, xj} i se noteaz cu
[xi, xj]. [xi, xj] i [xj, xi] reprezint aceeai muchie a grafului. Graful G are m muchii:
numrul de muchii = card(U) = m
Numim noduri adiacente orice pereche de noduri care formeaz o muchie - {xi, xj}U.
Fiecare dintre cele dou noduri (xi i xj) este nod incident cu muchia uk = [xi , xj].
Nodurile vecine unui nod xi sunt toate nodurile xj care sunt adiacente cu el.
Se numete nod extrem al unei muchii oricare dintre cele dou noduri care se gsesc la
captul muchiei. Nodurile xi, i xj sunt extremitile muchiei [xi, xj].
Se numesc muchii incidente dou muchii ui i uj care au o extremitate comun - nodul xk.
Un graf neorientat G este definit de o pereche de mulimi: mulimea nodurilor sale - X
i mulimea muchiilor sale - U. El poate fi considerat ca o mulime de noduri din care
unele pot fi unite dou cte dou printr-o muchie.
Graful se reprezint n plan prin intermediul unor elemente geometrice: nodurile se
reprezint prin cercuri, iar muchiile prin linii drepte anumite cercuri.
Nodul xi
Muchia uk = [xi , x]
Nodul xj
Dac graful neorientat G are n noduri (x1, x2, ..., xn), atunci numrul total de grafuri
neorientate care se pot forma cu aceste noduri este g:
g= 2
Cn2
Nodul unui graf este caracterizat prin grad.Gradul unui nod xk al grafului G este egal cu
numrul muchiilor incidente cu nodul i se noteaz cu d(xk).Se numete nod terminal un
nod care are gradul egal cu 1 : d(xk) = 1 (este incident cu o singur muchie).Se numete
nod izolat un nod care are gradul egal cu 0 : d(xk) = 0 (nu este adiacent cu nici un alt nod
al grafului, adic nu se gsete n extremitatea nici unei muchii).
Exemplul 1:
Graful G4=(X4,U4) din figura 4 este definit astfel: X4={1,2,34,5,6,7,8,9,10,11}
U4={[1,2], [1,4], [2,3], [2,5], [3,4], [3,5], [5,6], [5,7], [5,8] [7,9]}. n graful G4:
Gradul nodului 5 este 5, deoarece are 5 muchii incidente: [2,5], [3,5], [5,6], [5,7] i
[5,8].
Nodul 9 este nod terminal, deoarece are gradul 1 (o singur muchie incident: [7,9]).
Nodul 10 este nod izolat, deoarece are gradul 0 (nicio muchie incident).
Fig.4
10
11
Graful G4
ntr-un graf cu n noduri, oricare ar fi nodul xk, gradul su este mai mare sau egal cu 0 i
mai mic sau egal cu n-1 (0 d(xk) n-1).Dac graful G are m muchii (u1, u2,. ., um) i n
noduri (x1, x2,.... xn), atunci ntre gradul nodurilor i numrul de muchii exist urmtoarea
relaie: suma gradelor tuturor nodurilor grafului este egal cu dublul numrului de
muchii:
n
d (x
i 1
)=2m
Exemplul 2 :
n graful G4: d(1) + d(2) + d(3) + d(4) + d(5) + d(6) + d(7) + d(8) + d(9) + d(10) + d(11)
= 2+2+3+2+4+1 +2+1+1+0+0 = 18 = 2*9 = 2*m
Numrul minim de muchii, mmin, pe care trebuie s le aib un graf neorientat, cu n
noduri, ca s nu existe noduri izolate, este:
n 1
mmin=
2
Dac graful G are n noduri (n
Nodul xi al grafului G
i 1
i 1
d x i d - x i
I.2. Reprezentarea i implementarea grafului
Exist mai multe moduri de reprezentare la nivel logic a unui graf,care pot fi
implementate n memoria unui calculator,folosind diverse tipuri de structuri de
date.Aceste reprezentri pot fi folosite n algoritmii care prelucreaz grafuri i,implicit,n
programele prin care vor fi implementai n calculator aceti algoritmi.Printre modurile de
reprezentare a unui graf se numr
reprezentarea prin matricea de adiacen;
reprezentarea prin matricea de inciden;
reprezentarea prin lista muchiilor(arcelor);
reprezentarea prin lista de adiacen(listele vecinilor);
reprezentarea prin matricea costurilor.
Fiecare reprezentare prezint avantaje n ceea ce privete utilizarea eficient a memoriei
interne,n funcie de tipul grafului(cu noduri puine,dar cu muchii multe-sau cu noduri
multe,dar cu muchii puine) i din punct de vedere al eficienei algoritmilor de prelucrare
(n funcie de aplicaie).n urmtoarele reprezentri se consider c graful G=(X,U) are n
noduri i m muchii.
I.2.1.Reprezentarea prin matricea de adiacen
Matricea de adiacen a unui graf este o matrice ptrat binar de ordinul n(An,n),ale
crei elemente ai,I sunt definite astfel:
1
0
1
1
1
0
0
0
0
2
1
0
1
0
1
0
0
0
3
1
1
0
1
1
0
0
0
4
1
0
1
0
0
0
0
0
5
0
1
1
0
0
0
0
0
0
0
0
0
0
0
1
1
0
0
0
0
0
1
0
0
0
0
0
0
0
1
0
0
Graf orientat
Suma elementelor matricei de adiacen
este egal cu m(numrul de arce).
void main()
{int i; citeste(); cout<<Vecinii fiecarui nod sunt: <<endl;
for(i=1;i<=n;i++) {cout<<Nodul<<i<< ; vecini(i); cout<<endl;}}
Graful orientat-Programul 6
#include<fstream.h>
int a[10][10],n,m;
fstream f(graf3.txt,ios::in);
void citeste()
{int k,i,j; f>>n>>m;
for(k=1;k<=m;k++) {f>>i>>j; a[i][j]=1; a[j][i]=1;} f.close();}
void vecini(int i)
{for(int j=1;j<=n;j++) if (a[i][j]==1|| a[j][i]==1) cout<<j<< ;}
void main()
{int i; citeste(); cout<<Vecinii fiecarui nod sunt: <<endl;
for(i=1;i<=n;i++) {cout<<Nodul<<i<< ; vecini(i); cout<<endl;}}
4.Generarea matricei de adiacen.
Pentru a testa programele care prelucreaz grafuri implementate cu matricea de
adiacen, se pot genera aleatoriu matricea de adiacen.n programul 7,funcia
generare() genereaz matricea de adiacen a unui graf neorientat,cu n noduri i m
muchii.
Programul 7
#include<iostream.h>
#include<stdlib.h>
int a[10][10],n,m;
void generare()
{int k=0,i,j; randomize();
while(k<m)
{i=rand() %n+1; j=rand()%n+1;
if(i!=j && a[i][j]==0) {a[i][j]=1; a[j][i]=1; k++;}}}
void main()
{cout<<n= ; cin>>n; cout<<m= ; cin>>m;
while(m>n*(n-1)/2} {cout<<m= ; cin>>m;}
generare(); }
1, dac [i,j]
0, dac [i,j]
U4
U3
4
U9
U7
U6
Graful G1
Proprietaile matricei de inciden a grafului neorientat:
1.Pe fiecare coloan exist dou elemente cu valoarea 1 (pe liniile i i j care corespund
nodurilor incidente cu muchia),iar restul elementelor au valoarea 0.
2.Matricea de inciden are 2xm elemente egale cu 1, deoarece fiecare muchie este
incident cu dou noduri.
Matricea de inciden a unui graf orientat este o matrice cu n linii i m coloane
(An,m),ale crei elemente ai,j sunt definite astfel:
1, dac nodul i este extremitatea final a arcului j
a i,j= -1,dac nodul i este extremitatea iniial a arcului j
0,dac nodul i nu este extremitate a arcului j
Implementarea grafului orientat prin matricea de inciden se face printr-un tablou
bidimensional (o matrice cu dimensiunea nxm),astfel:
int a[<n>][<m>]
U1
U3
1
U2
U4 U5
U6
U7
U10
4
U8
U9
Graful orientat G9
-1
-1
-1
-1
-1
-1
-1
-1
-1
-1
Graf orientat
Gradul unui nod i este egal cu suma Gradul intern al unui nod i este egal cu
elementelor de pe linia i
numrul de elemente cu valoare 1 de pe
linia i. Gradul extern al unui nod i este egal
cu numrul de elemente cu valoarea -1 de
pe linia i
Nodurile adiacente nodului i sunt nodurile
j(j=1,n )pentru care elementele din linia j
sunt egele cu 1 n coloana k (k=1,m) n
care i elemente de pe linia i au valoarea 1:
a[i][k]=1 i a[j][k]=1
Numrul de vecini ai nodului i este egal cu Numrul de vecini ai nodului i este egal cu
gradul nodului.
cardinalul mulimii de noduri adiacente
nodului i
Muchia k=[i,j] a grafului este determinat Arcul k=[i,j] al grafului este determinat de
de dou elemente ale matriceii a[i]kj] i dou elemente ale matricei ,a[i]kj] i
a[j]kj],care ndeplinesc condiia a[i][k]=1 a[j]ki],care ndeplinesc condiia a[i][k]=-1
i a[j][k]=1 i semnific faptul c i a[j][k]=1 i semnific faptul c arcul k
muchia k este incident cu nodurile i i j
iese din nodul i i intr n nodul j
Implementarea algoritmilor pentru reprezentarea grafurilor cu matricea de
inciden
1.Crearea matricei de inciden prin introducerea datelor de la tastatur.Determinarea
gradului unui nod .Salvarea matricei de inciden ntr-un fisier text.
Se citesc de la tastatur muchiile(arcele)unui graf orientat(neorientat).Se creaz matricea
de inciden a grafului.Se afieaz gradul nodului p a crui etichet se introduce de la
tastatur.Se salveaz matricea de inciden n fiierul graf5.txt , pentru graful neorientat i
graf6.txt pentru graful orientat.n fiierul text se scriu pe primul rnd ordinal grafului i
numarul de muchii,iar pe urmtoarele rnduri,liniile matricei de inciden.Funcia scrie( )
se folosete pentru a scrie matrice de inciden n fiier.
Graful neorientat .n programul 1,funcia grad( )se folosete pentru a determina gradul
unui nod.
Programul 1
#include <fstream.h>
int a[10][10],n,m;
fstream f(graf5.txt,ios::out);
void scrie( )
a[i][k]=-1; a[j][k]=1; }
cout<<nodul= ; cin>>p;
cout<<Gradul intern al nodului <<p<< este <<grad_int (p)<<endl;
cout<<Gradul extern al nodului <<p<< este <<grad_ext (p)<<endl;
scrie( ) ; }
2.Crearea matricei de inciden prin citirea datelor din fiier.Afiarea vecinilor unui
nod.
Se citesc din fiierele create anterior (graf5.txt,graf6.txt) matricele de inciden ale
celor dou grafuri i se afieaz vecinii unui nod x a crui etichet se introduce de la
tastatur. Funcia
citete ( ) se folosete pentru a citi matricea de inciden din fiier
Graf neorientat. n programul 3,funcia vecini( ) se folosete pentru a determina vecinii
unui nod.
Programul 3
#include<fstream.h>
int a [10][10],n,m;
fstream f (graf5.txt,ios: :in ) ;
void citete( )
{ int i,k ; f>>n>>m;
for (i=1; i<=n; i++)
for (k=1;k<=m; k++) f>>a[i] [k]; f.close( ); }
void vecini (int i)
{ int k,j;
for (k=1;k<=m; k++)
if (a[i] [k] = =1)
for (j=1 ; j<=n ; j++)
if (j!=0 && a[j][k]= =1)
cout<<j<< ;}
void main( )
{int p;
cout<<nodul= ;
cin>>x; citete ( );
cout<<vecinii nodului<<x<<sunt nodurile;
vecinii(x);}
Graf orientat.
n programul 4,vectorii binari s i p se folosesc pentru a memora succesorii, respectiv
predecesorii nodului x.Elementul i are valoarea 1dac nodul i este succesor,respectiv
predecesor al nodului x;altfel are valoarea 0.Funciile succ( ) i pred( ) se folosesc pentru
a determina n vectorii s i p succesorii,respective predecesorii unui nod.Funcia vecini( )
se folosete pentru a determina vecinii unui nod,prin reuniunea mulimii predecesorilor
i succesorilor.
Programul 4
#include<fstream.h>
int a [10][10],n,m,s[10],p[10];
grafului i apoi,pe cte un rnd,separate prin spaiu,cele dou noduri terminale ale
fiecrei muchii(arc).Se folosesc matricele a pentru matricea de adiacen i b pentru
matricea de inciden i funciile citete() pentru a citi matricea de adiacen din
fiier,salveaz()pentru a salva n fiierul text informaiile despre muchiile(arcele)
grafului, transform() pentru a obine matricea de inciden din matricea de adiacen,
afieaz_noduri_izolate() pentu a afia nodurile izolate i afieaz_muchii( ) pentru a
afia muchiile (arcele).
Graful neorientat-Programul 7
#include<fstream.h>
int a [10][10],n,m,b[10][20];
fstream f 1(graf1.txt,ios: :in ) ,f 2(graf9.txt,ios: :out ) ;
void citete( )
{ int i,j ; f>>n;
for (i=1; i<=n; i++)
for (j=1;j<=n; j++) { f1>>a[i] [j];
if(a[i][j]==1) m++;}
m=m/2; f1.close( );}
void transforma( )
{int i,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<i;j++)
if(a[i][j]==1)
{b[i][k]=1; b[j][k]=1; k++;}}
void afieaz muchii( )
{ for (k=1;k<=m;k++) {cout<<muchia<<k<<: ;
for (int i=1; i<=n; i++)if(b[i][k]==1)
cout<<i<< ;
cout<<endl;}}
void afieaz_noduri_izolate( )
{ int i,k,x;
for (i=1; i<=n; i++)
{for (k=1,x=0,k<=m && x==0;k++)
if(b[i][k]==1) x=1;
if(!x)
cout>>i<< ;}}
void salveaz( )
{f2<<n<< <<m<<endl;
for (int k=1;k<=m;k++)
{ for (int i=1; i<=n; i++)if(b[i][k]==1)
f2<<i<< ;
f2<<endl;}
f2.close( );}
void main( )
{citete ( ); transform( ); afieaz_muchii( );
cout<<noduri izolate sunt:
afieaz_noduri_izolate( );
salveaz( );}
Graful orientat-Programul 8
#include<fstream.h>
int a [10][10],n,m,b[10][20];
fstream f 1(graf1.txt,ios: :in ) ,f 2(graf9.txt,ios: :out ) ;
void citete( )
{ int i,j ; f>>n;
for (i=1; i<=n; i++)
for (j=1;j<=n; j++) { f1>>a[i] [j];
if(a[i][j]==1) m++;}
f1.close( );}
void transforma( )
{int i,j,k=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]==1){b[i][k]=-1; b[j][k]=1; k++;}}
void afieaz_arce( )
{int i,k,x,y;
for (k=1;k<=m;k++)
{cout<<arcul<<k<<: ;
for (i=1; i<=n; i++)
if(b[i][k]==-1) x=i;if(b[i][k]==1) y=i;}
cout<<x<< -<<y<<endl;}}
void afieaz_noduri_izolate( )
{ int i,k,x;
for (i=1; i<=n; i++)
{for (k=1,x=0,k<=m && x==0;k++)
if(b[i][k]==1| | b[i][k]==-1) x=1;
if(!x)cout>>i<< ;}}
void salveaz( )
{int i,k;
f2<<n<< <<m<<endl;
for ( k=1;k<=m;k++)
{ for ( i=1; i<=n; i++){if(b[i][k]==-1) x=i;
if(b[i][k]==1) y=i;}
f2<<x<< -<<y<<endl;}f2.close( );}
void main( )
{citete ( ); transform( ); afieaz_arce( );
cout<<noduri izolate sunt:
afieaz_noduri_izolate( );salveaz( );}
II.2.3. Reprezentarea prin lista de adiacen
Lista de adiacen este format din listele Li (1in) care conin toi vecinii unui nod xi
la care se poate ajunge direct din nodul xi , adic toate nodurile xj pentru care [xi, xj] U.
Observaie. n cazul grafului neorientat, lista Li a vecinilor unui nod xi al grafului este
format din nodurile xj adiacente nodului xi. n cazul grafului orientat, lista Li a vecinilor
unui nod xi al grafului este format din nodurile xj care sunt succesorii nodului xi.
Nod
Graful neorientat G1
1
2
3
4
5
6
7
8
U3
1
U2
U4 U5
U6
U7
U10
4
U8
Lista de
adiacen
2
1,3,4
2,5
3,6
Nod
Graful orientat G9
U9
Lista de
adiacen
2,3,4
1,3,5
1,2,4,5
1,3
2,3
7,8
6
6
L[1][n]).
Gradul extern al nodului i este egal, cu
lungimea listei de adiacen a nodului.
Gradul intern al nodului i, este egal cu
numrul de apariii ale etichetei nodului n
a doua seciune a primei linii a matricei
(L[0][j]=i, cu j=n+1, n+m).
muchii ale grafului,traseul fiind ordinea n care se parcurg aceste muchi.Fiecare pereche
de noduri succesive din lan reprezint parcurgerea unei muchii.Dac exist L(xi,xj),se
spune c nodul xj este accesibil din nodul xi..
Graful orientat
Dac mulimea nodurilor unui graf orientat este X={ x1,x2xn},un lan de la nodul 1 la
nodul kL(l1,lk) va fi definit prin mulimea L(l1,lk)= L(l1,lk)={l1,l2,li..lk},unde li X ,pentru
orice i(1 i
). La definirea unui lan, nu se ine cont de orientarea arcelor,ci numai de
faptul c dou noduri sunt legat de de un arc.
Lungimea unui lan reprezint numrul de parcurgeri ale muchiilor, respective arcelor.
Dac o muchie (un arc) este parcurs de mai multe ori,se va numra fiecare din
parcurgerile sale.
Lanul de lungime minim dintre nodul xi. i nodul xj Lmin(xi,xj)-este lanul cu numrul
minim de muchii(arce),din mulimea nevid de lanuri L(xi,xj).Extremitile unui lan sunt
formate din nodul care ncepe i nodul cu care se termin lanul.
Exemple:
1.Pentru un graf neorientat G19=(X19,U19),definit astfel:
mulimea nodurilor este X19={1,2,3,4,5,6,7,8}.
mulimea
muchiilor
este
U19={[1,2],[1,5],[1,6],[2,3],[2,5],[2,6],[3,4],[3,6],[3,7],[3,8],[4,8],[5,6],[6,7],[7,8]}.
L1(1,7)={1,2,3,8,4,3,6,5,2,3,7}este un lan ntre nodul cu eticheta 1 i nodul cu
eticheta 7 (figura 23).Lungimea lanului este 10.
L1(1,7) definit anterior este un lan neelemetar,deoarece se repet nodul cu
eticheta 3.Este un lan compus,deoarece n lan se repet muchia [2,3].
L2(1,7)={1,2,3,6,7} este un lan elementar deoarece fiecare nod este parcurs o
singura dat.
L3(1,7)={1,6,3,2,6,7} este un lan simplu,deoarece nici o muchie nu se repet,dar
este un lan neelementar,deoarece se repet nodul cu muchia 6.
Fig.23
G19
Fig.24 G20
L1(1,5) definit anterior este un lan neelementar,deoarece se repet nodul cu
eticheta 6.Este un lan compus,deoarece n lan se repet arcul[6,7]
L2(1,5)={1,2,3,7,6,5} este un lan elementar, deoarece fiecare nod este parcurs o
singur dat.
L3(1,5)={1,2,4,5,2,3,6,5} este un lan simplu,deoarece nici un arc nu se repet,dar
este un lan neelementar deoarece se repet nodul cu eticheta 2.
Funcia citete ( ) se folosete pentru a citi matricea de adiacen din fiier. Variabila este
se folosete pentru a verifica dac s-a gsit un lan elementar ntre cele dou noduri (are
valoarea 0 False, dac nu s-a gsit un lan elementar).
Programul 1
#include<fstream. h>
typedef stiva [100] ;
int a [20][20] , n , k , as , ev , x , y , este=0 ;
stiva st ;
fstream f ( graf1.txt , ios : :in ) ;
void citeste ( ) { // se citeste matricea de adiacenta din fisier }
void init ( ) {st [k]=0; }
int successor ( )
{if ( st [k]<n) {st [k]=st [k]+1; return 1;} else return 0;}
int valid ( )
{if ( k>1) //conditia ca doua noduri successive sa fie adiacente
if ( a[ st [k-1] ] [st [k]] = = 0) return 0;
//pentru graful orientat
// if (a[ st [k]] [st [k-1]] = =0 && a[st [k-1]] [st [k]] = =0) return 0;
for ( int i=1;i<k;i++) //conditia ca lantul sa fie elementar
if ( st [k] = =st [i] ) return 0;
return 1; }
int solutie ( ) { return st [k] = =y; }
//se obtine solutia atunci cand ultimul nod adaugat in stiva este y
void tipar ( )
{ for ( int i=1, este=1; i<=k; i++) cout<<st [i]<< ; cout<<endl; }
void bt ( ) { //partea fixa a algoritmului }
{k=2; init ( ) ;
while ( k>1 )
{ as=1; ev=0;
while ( as && !ev)
{as=successor ( ) ;
if (as)
ev=valid ( ) ;}
if (as)
if (solutie ( ) ) tipar ( ) ;
else { k ++; init ( ) ; }
else k -- ; } }
void main ( )
{ citeste ( ) ; cout<<x= ; cin>>x; cout<<y= ; cin>>y; st [1] =x; bt ( ) ;
if (!este) cout<<Nu exista lant ; }
2.Afiarea tututror lanurilor elementare din graf.
Algoritmul. Pentru generarea tuturor lanurilor elementare din graf, se vor genera lanurile
elementare dintre nodul x (1xn) i nodul y (1yn), folosind metoda backtracking, care
se va apela pentru ficare pereche de noduri x i y (xy).
Implementarea algoritmului. n programul 2,se citete din fiierul text graf1.txt matricea
de adiacen a unui graf neorientat, respectiv, din fiierul graf2.txt matricea de aciacen a
unui graf orientat. Se caut toate lanurile elementare care exist n graf i se afieaz.
Dac nu exist nici un lan elementar, se afieaz un mesaj.
Programul 2
#include<fstream. h>
typedef stiva [100] ;
int a [20][20] , n , k , as , ev , x , y , este=0 ;
stiva st ;
fstream f ( graf1.txt , ios : :in ) ;
void citeste ( ) {//la fel ca n exemplul precedent }
void init ( ) {//la fel ca n exemplul precedent }
int succesor ( ) {//la fel ca n exemplul precedent }
int valid ( ) {//la fel ca n exemplul precedent }
int solutie ( ) {//la fel ca n exemplul precedent }
void tipar ( ) {//la fel ca n exemplul precedent }
void bt ( ) {//partea fix a algoritmului - ca n exemplul precedent }
void main ( )
{ citeste ( ) ;
for ( x=1;x<=n;x++ )
for ( y=1;y<=n;y++ ) if (x!=y) { st [1]=x; bt ( ) ;}
if ( !este )
cout<<Nu exista lanturi elementare ; }
3.Verificarea unui ir de etichete de noduri dac formeaz un lan simplu.
Algoritmul. Se verific dac:
-irul de etichete poate forma un lan (dac fiecare pereche de noduri consecutive din
lan este legat prin muchie, respectiv arc) ;
-lanul este simplu (se verific dac muchiile formate cu nodurile din lan nu se
repet).
Implementarea algoritmului. n programul 3,se citesc din fiierul text graf3.txt lista
muchiilor unui graf neorientat, respectiv, din fiierul graf.4txt lista arcelor unui graf
orientat. Se citete apoi, de la tastatur, un ir de k numere, care reprezint etichete ale
nodurilor din graf. Se verific dac acest ir de noduri poate reprezenta un lan simplu n
graf. irul de numere citite de la tastatur se memoreaz n vectorul v. n vectorul z cu
nregistrri de tip muchie, se memoreaz muchiile (arcele) pe care le formeaz dou
noduri succesive din irul de numere. Pentru a identifica dou muchii (arce) identice,
perechile de etichete care formeaz o muchie sunt memorate ordonat. Funcia citeste ( )
se folosete pentru a citi informaiile din fiier i pentru a le memora n matricea de
adiacen a grafului, funcia lant ( ) se folosete pentru a verifica dac irul de numere
poate reprezenta un lan din graf, funcia simplu ( ) se folosete pentru a verifica dac
lanul este un lan simplu.
Programul 3
#include<fstream. h>
struct muchie { int x, y ;} ;
muchie z [10];
int k, n, m, a [10][10], v [10] ;
fstream f ( graf3.txt, ios :: in) ;
void citeste ( )
{int i, x, y; f>>n>>m;
for (i=1;i<=m;i++) {f>>x>>y; a[x][y] =1; a [y][x] =1 ; } f.close ( ) ; }
int lant ( )
{for (int i=1;i<k;i++) if ( a[v[i]] [v[i+1]] ==0 ) return 0;
return 1;}
int simplu ( )
{for (int i=1;i<k;i++)
for (int j=i+1;j<=k;j++) if (z[i].x == z[j].x && z[i].y ==z[j].y) return 0;
return 1; }
void main ( )
{int i; citeste ( ); cout<<k= ; cin>>k;
for (i=1;i<=k;i++) {cout<<eticheta <<i<< = ; cin>>v[i] ; }
for (i=1;i<k;i++) if (v[i]<v[i+1] ) { z[i].x=v[i]; z[i].y=v[i+1] ;}
else { z[i].x=v[i+1]; z[i].y=v[i]; }
if ( lant ( ) )
if ( simplu ( ) ) cout<<este lant simplu ;
else cout<<nu este lant simplu ;
else cout<<nu este lant ; }
Ciclul
Un lan care are toate muchiile distincte dou cte dou i extremiti care coincide se
numete ciclu.Ciclul este un lan simplu ( [l1,l2] [l2,l3]; [l1,l2] [l3,l4]; ; [l1,l2] [lk1,lk]; [lk-2, lk-1] [lk-1,lk]), n care extremitile coincid: l1=lk.
Un graf fr cicluri se numete graf aciclic.
Dac toate nodurile unui ciclu sunt distincte dou cte dou, cu excepia extremitilor,
ciclul se numete ciclu elementar.
Exemple:
1.Pentru graful neorientat G19 , figura 23:
Lanul L4(1,1) = {1,2,3,6,2,1} nu este un ciclu deoarece n lan se repet muchia
[1,2].
Lanul L5(1,1) = {1,2,6,3,7,6,1}= C1 este un ciclu neelementar deoarece se repet
nodul cu eticheta 6.
Lanul L6(1,1) ={1,2,3,7,6,1}= C2 este un ciclu elementar deoarece nu se repet
nici un nod.
2. Pentru graful orientat G20, figura 24:
Lanul L4(1,1) ={1,2,4,5,2,1} nu este un ciclu deoarece n lan se repet arcul
[1,2].
Lanul L5(1,1) = {1,2,5,6,3,2,4,1}= C1 este un ciclu neelemntar deoarece se repet
nodul cu eticheta 2.
Lanul L6(1,1) = {1,2,3,6,5,4,1} este un ciclu elementar deoarece nu se repet nici
un nod.
3. Un circuit electric poate fi reprezentat cu ajutorul unui graf orientat, n care nodurile
reelei sunt nodurile grafului, iar sensul arcelor este dat de sensul ales pentru curentul
electric.
{ citeste ( );
for ( x=1;x<=n;x++ ) { st[1]=x; bt ( ) ;}
if ( !este ) cout<<nu exista nici un ciclu elementar ; }
Drumul
ntr-un graf orientat G=(X,U) se definete un drum ca fiind o succesiune de noduri care
au proprietatea c oricare ar fi dou noduri successive ele sunt legate printr-un arc.
Dac, ntr-un graf orientat, mulimea nodurilor este X={x1,x2,,xn}, iar mulimea
arcelor este U={u1,u2,,um}, un drum de la nodul d1 la nodul dk D(d1,dk) va fi definit
prin mulimea nodurilor D(d1,dk)={d1,d2,,dk}, unde di U, pentru orice i (1ik), iar
arcele [d1,d2],[d2,d3],[d3,d4],, [dk-1,dk] U. Drumul poate fi privit ca un lan n care
parcurgerea de la un nod la altul trebuie s se fac n sensul arcului care leag nodurile.
Dac exist D(xi,xj), se spune c nodul xj este accesibil din nodul xi.
Lungimea unui drum este dat de numrul de arce care l compun. n cazul n care
arcele au asociate lungimi, lungimea unui drum este dat de suma lungimilor
arcelor care l compun.
Drumul de lungime minim dintre nodul di i nodul dj Dmin(di,dj) este drumul
cu numrul minim de arce din mulimea nevid de drumuri D(di,dj).
Subdrumul este format dintr-un ir continuu de noduri din drum. De exemplu,
pentru lanul D(d1,dk)={d1,d2,, di,.dj,,dk}, Ds(di,dj) definit astfel:
Ds(di,dj)={di,di+1,,dj-1,dj } este un subdrum al drumului D.
Drumul elementar este drumul n care nodurile sunt distincte dou cte dou.
Drumul simplu este drumul n care arcele sunt distincte dou cte dou.
Exemple Pentru graful orientat G20 (figura 24):
Lanul L7(1,6) = {1,2,5,6} nu este un drum deoarece parcurgerea nu se face n
sensul sgeilor.
Lanul L8(1,6) ={1,2,3,6,3,6} = D1 este un drum neelementar, deoarece se repet
eticheta nodurilor 3 6 i compus deoarece prin arcul [3,6] s-a trecut de dou
ori.
Lanul L9(1,6) ={1,2,3,7,6} = D2 este un drum elementar, deoarece nu se repet
nici un nod.
Lanul L9(1,6) = {1,2,4,5,2,3,6} = D3 este un drum simplu, deoarece nici un arc nu
a fost parcurs de dou ori, dar este un drum neelementar, deoarece se repet nodul
cu eticheta 2.
Algoritmi pentru determinarea drumurilor elementare ntr-un graf orientat
1.Afiarea drumurilor elementare din graf.
Algoritmul. Se va folosi algoritmul pentru determinarea tuturor lanurilor elementare din
graf, la care elementul soluiei generat n stiv, la nivelul k (k>1), va fi considerat valid
numai dac trecerea de la nodul de pe nivelul k-1 la nodul de pe nivelul k se face, n graf,
n sensul arcului.
Implementarea algoritmului. n programul 5,se citete din fiierul graf2.txt matricea de
adiacen a unui graf orientat. Se caut toate drumurile care exist n graf i se afieaz.
Dac nu exist nici un drum elementar, se afieaz un mesaj.
Programul 5
#include<fstream.h>
typedef stiva [100];
int a [20][20] , n , k , as , ev , x , este=0 ;
stiva st ;
fstream f ( graf1.txt , ios : :in ) ;
void citeste ( ) { //se citete matricea de adiacen din fiier }
void init ( ) { //este identic cu cea de la afiarea lanurilor elementare }
int valid ( )
{ if ( k>1) if ( a[st [k-1]][st[k]] == 0 ) return 0;
for ( int i=1; i<k; i++ ) if ( st [k] == st [i] ) return 0;
return 1;}
int solutie ( ) { return st [k] ==y; }
void tipar ( )
{ for ( int i=1, este=1; i<k;i++ ) cout<<st[i]<< ; cout<<x<<endl; }
void bt ( ) { // partea fix a algoritmului }
void main ( )
{ citeste ();
for (x=1;x<=n;x++)
for ( y=1;y<=n;y++ ) if ( x!=y ) { st [1]= x; bt ( ); }
if ( !este ) cout<<nu exista ; }
2.Algoritmul Roy-Warshall de determinare a matricei drumurilor
Matricea drumurilor este o matrice ptrat binar de dimensiune n (n reprezentnd
ordinal grafului), definit astfel:
a[i][j] =
Informaiile din matricea drumurilor se pot folosi pentru a verifica dac exist drum
ntre dou noduri ale grafului.
Algoritmul. Dac nu exist nu arc de la nodul i la nodul j, considerm c exist un drum
de la nodul i la nodul j, dac exist un nod k (ki i kj) care are proprietarea c exist un
drum de la nodul i la nodul k i exist un drum de la nodul k la nodul j. Matricea
drumurilor se obine din matricea de adiacen prin transformri succesive, astfel: se
genereaz toate nodurile k (1kn), iar pentru fiecare nod k se genereaz toate perechile
de noduri i (ik) i j (jk) i se verific dac a[i][k] =1 i a[k][j] =1. n caz afirmativ, n
matricea de adiacen se atribuie valoarea 1 elementului a[i][j].
2
3
Fig.26
G22
Pentru graful G22 din figura 26 matricea de adiacen sufer urmtoarele cinci
transformri.
La fiecare transformare, dac drumul de la nodul i la nodul j trece prin nodul intermediar
k (drumul trece de la nodul i la nodul k i de la nodul k la nodul j), atunci elementului
a[i][j] i se va atribui valoarea 1.
Matricea de adiacen este:
k=1
1
0
0
1
0
1
1
0
0
1
0
0
0
0
0
0
0
0
0
1
1
0
0
0
1
0
0
1
0
1
0
0
0
1
0
0
0
0
0
1
0
1
0
0
0
0
0
k=2
0
0
1
0
0
1
0
1
0
0
1
1
1
0
0
k=3
0
0
1
0
1
0
0
0
1
0
1
1
1
0
0
1
1
1
0
0
1
1
1
0
0
k=4
k=5
1
1
1
0
1
0
0
0
1
0
Interpretarea datelor din matricea obinut n urma transformrilor se face astfel: exist
drum de la nodul i la nodul j dac a[i][j] =1. De exemplu, exist drum de la nodul 2 la
nodul 4, dar nu exist drum de la nodul 4 la nodul 2.
Implementarea algoritmului. n programul 6,se citete din fiierul graf20.txt matricea de
adiacen a unui graf orientat. Se afiesz toate perechile de noduri din graf ntre care
exist un drum. Funcia citeste ( ) se folosete pentru a citi matricea de adiacen din
fiier. Funcia transforma ( ) se folosete pentru a transforma matricea de adiacen n
matricea drumurilor. Matricea de adiacen va suferi n transformri succesive (pentru
fiecare nou valoare a lui k), astfel: fiecare element a[i][j] cu ik i jk, este nlocuit cu
valoarea produsului a[i][k]*a[k][j] ceea ce este echivalent cu a atribui valoarea 1
acestui element dac a[i][k] =1i a[k][j] =1. Funcia afiseaza ( ) se folosete pentru a
afia toate perechile de noduri i i j ntre care exist drum. Aceste perechi sunt
identificate n matricea drumurilor ca fiind indicele pentru linie i indicele pentru coloan
ale elementelor care au valoarea 1.
Programul 6
#include<fstream.h>
int a [20][20], n;
fstream f (graf20.txt, ios :: in);
void citeste ( ) { se citete matricea de adiacen din fiier}
void transforma( )
{ for ( int k=1; k<=n; k++ )
for ( int i=1; i<=n; i++ )
for ( int j=1; j<=n; j++ )
if ( a[j][j] ==0 && i!=k && j!=k ) a [i][j] = a[i][k]*a[k][j]; }
void afiseaza( )
{ cout<< exista drum intre perechile de noduri <<endl;
for ( int i=1;i<=n; i++ )
for ( int j=1; j<=n; j++ )
if ( a[i][j] ==1 && i!=j ) cout<< ( <<i<< , <<j<< ) << ; }
void main ( ) { citeste( ); transforma( ); afiseaza( ); }
Complexitatea algoritmului Roy-Warshall
Algoritmul de transformare a matricei de adiacen n matricea drumurilor are ordinal de
complexitate O(n*n*n)=O(n3), deoarece fiecare structur repetitiv for se execut de n
ori, iar structurile for sunt imbricate.
Circuitul
ntr-un graf orientat un drum care are toate arcele distincte dou cte dou i extremiti
care coincid se numete circuit.
Circuitul este un drum simplu (arcele sunt distincte dou cte dou n care extremitile
coincid).
Circuitul elementar este circuitul n care toate nodurile sunt distincte dou
cte dou,cu excepia primului i a ultimului-care coincid.
Exemple pentru graful orientat G20, figura 24 :
Lanul L10(1,1)={1,2,3,6,3,6,3,7,6,5,4,1}nu este un circuit, deoarece arcele [3,6]
si [6,3] au fost parcurse de dou ori.
Lanul L11(1,1)={1,2,3,6,7,5,2,4,1}=C1 este un circuit neelementar,deoarece se
repet eticheta nodurilor 3 i 6.
Lanul L12(1,1)={1,2,3,7,6,5,4,1}=C2 este un circuit elementar , deoarece nu se
repet eticheta nici unui nod.
Algoritm pentru determinarea circuitelor elementare ntr-un graf orientat:
Programul 7
#include <fstream.h>
typedef stiva[100];
int a[20][20],n,k,as,ev,x,este=0;
stiva st;
fstream f(graf2.txt,ios:; in);
Exemplul 1:
Graful G20
1)Graful orientat G20=(X20,U20) este un graf tare conex , deoarece exist un circuit
elementar care trece prin toate nodurile grafului:{1,2,3,7,6,4,1} , altfel spus ,oricare ar fi
dou noduri din mulimea X20 , ele pot fi legate printr-un drum.
Dac un graf G=(X,U) nu este conex , se numete component tare conex a grafului un
subgraf conex C= (X` ,U`) al su , maximal n raport cu aceast proprietate (conine
numrul maxim de noduri din G care au proprietatea c sunt legate printr-un drum).
Un graf tare conex are o singur component tare conex(graful nsui).
Componenta tare conex din care face parte un nod este dat de intersecia dintre
subgraful predecesorilor i subgraful succesorilor acelui nod.
Graful componentelor tare conexe ale unui graf care nu este tare conex G=(X,U) se
obine prin reducerea fiecrei componente conexe la un nod.
Exemplul 2 :
n graful orientat din figura 29 ,G25 = (X25,U25) :
Fig.29
Componentele tare conexe sunt C1={1,2,3} , C2={4,5,6} i C3={7}
Algoritmi pentru determinarea conexitii grafurilor
1.Determinarea componentelor conexe ntr-un graf.
Algoritmul. O component conex este format din toate nodurile ntre care exist un lan
elementar. Deoarece un nod nu poate s aparin dect unei componente conexe, se va
folosi un vector cu n elemente pentru a memora nodurile care au fost deja nregistrate
ntr-o component conex. Iniial, elementele vectorului au valoarea 0 (niciun nod nu a fost
nregistrat ntr-o component conex), iar dac un nod x va fi adugat la o component
conex, valoarea elementului x din vector va fi 1. Pentru a verifica dac exist un lan
elementar ntre dou noduri x i y se folosete metoda backtracking.Acest algoritm poate fi
folosit att n grafurile neorientate, ct i n grafurile orientate. Mai poate fi folosit i pentru
a verifica dac un graf este conex : fie se verific dac ntre nodul 1 i fiecare dintre
celelalte noduri ale grafului exist un lan elementar, fie se verific dac prima component
conex obinut conine toate nodurile grafului.
Implementarea algoritmului. n programul 1, se citete din fiierul graf19.txt matricea de
adiacen a unui graf neorientat (varianta din fiierul graf20.txt matricea de adiacen a
unui graf orientat) i se afieaz componentele conexe. n vectorul v se memoreaz
nodurile care au fost deja nregistrate ntr-o component conex. Variabila este se folosete
pentru a verifica dac s-a gsit un lan elementar ntre dou noduri (are valoarea 0 False,
dac nu s-a gsit un lan elementar). Variabila m se folosete pentru a numra
componentele conexe identificate. Funcia citete () se folosete pentru a citi matricea de
adiacen din fiier. Funcia componente() se folosete pentru a afia componentele conexe
ale grafului: pentru fiecare nod x (1xn ) care nu a fost afiat ntr-o component conex
(v[x]= 0), se caut toate nodurile y (1yn i yx) care sunt legate cu un lan elementar de
nodul x. Pentru un nod y gsit, se marcheaz n vectorul v faptul c a fost adugat la o
component conex (v[y]= 1). Programul 1
#include<fstream.h>
typedef stiva [100];
int a [20][20], n, k, as, ev, x, y, v[20], este =0;
stiva st;
fstream f (graf19.txt)
void citete () (// se citete matricea de adiacen din fiier)
void init ()
(//identic cu cea de la afiarea lanurilor elementare)
int succesor () (//identic cu cea de la afiarea lanurilor elementare)
int valid ()
(// identic cu cea de la afiarea lanurilor elementare)
int solutie () {return st [k]==y;}
// se obine soluia atunci cnd ultimul nod adugat n stiv este y.
void tipar () {este=1;}
// dac exist soluie (un lan ntre nodurile x i y)
// variabila este va avea valoarea 1.
void bt () { // identic cu cea de la afiarea lanurilor elementare}
void component ()
{int m = 0;
for ( x=1; x<=n; x++)
if (v[x]== 0)
{m++ ; st[1]=x; v[x]= 1;
cout<< componenta conex<<m<<: <<x<<_ ;
for(y=1; y<=n; y++)
if (x!= y) {este= 0; bt();
if (este) { v[y]= 1; cout<<y<< ; }}
cout<<endl; }}
void main()
{citeste(); componente ();}
2
3
Matricea de adiacen
Implementarea algoritmului. n programul 2,se citete din fiierul graf20.txt matricea de
adiacen a unui graf orientat i se determin dac graful este conex. Dac nu este, se
afieaz componentele conexe. n vectorul v se memoreaz nodurile care au fost deja
nregistrate ntr-o component conex. Funcia citeste () se folosete pentru a citi
matricea de adiacen n fiier. Funcia transforma() se folosete pentru a afia
componentele conexe ale grafului pentru fiecare nod i(1in) care nu a fost afiat ntr-o
component conex (v[i]=0), se caut toate nodurile j (1jn i ji) la care ajunge un
drum ce pornete din nodul i . Pentru un nod j gsit, se marcheaz n vectorul v faptul c
a fost adugat la o component conex (v[j]=1).
Programul 2
#include<fstream.h>
typedef stiva[100]
int a [20] [20], n, y[20];
fstream f(graf20.txt, ios::in);
void transforma()
{for (int k=1;k<=n; k++)
for (int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if ( a[i][j]==0 && 1!=k && j!=k)
a[i][j] = a[i][k]*a[k][j];}
void component()
{int i, j, n=0;
for(int i=1; i<=n; i++)if (v[1]==0)
{m++; v[i] =1; cout<<component conexa<<m<<: <<i<<_;
for (int j=1; j<=n; j++)
if(a[i][j] ==1 && i!=j)
{v[j]=1; cout<<j<< ;}
cout<<endl;}}
void main()
{citeste() ; transforma() ; componente();}
3. Determinarea componentelor tare conexe ntr-un graf orientat.
Algoritmul. O component tare conex este format din toate nodurile i i j ntre care
exist un drum elementar de la nodul i la nodul j, dar i invers. Se folosete un vector cu
n elemente, pentru a memora nodurile care au fost deja nregistrate ntr-o component
tare conex. Iniial, elementele vectorului au valoarea 0, iar dac un nod i va fi adugat la
o component conex, atunci i=1.
Implementarea algoritmului.Se folosete metoda backtracking.n programul 3,se citete
din fiierul graf20.txt matricea de adiacen a unui graf orientat. Dac nu este conex se
afieaz componentele tare conexe. Variabila este1 se folosete pentru a verifica dac s-a
gsit un drum elementar de la nodul i la nodul j. Variabila este2 se folosete pentru a
verifica dac s-a gsit un drum elementar de la nodul j la nodul i, iar variabila este se
folosete pentru a verifica dac s-a gsit un drum elementar de la nodul x la nodul y. n
vectorul v se memoreaz nodurile care au fost deja nregistrate ntr-o component tare
conex. Variabila m se folosete pentru a numra componentele conexe identificate.
Funcia citeste() se folosete pentru a citi matricea de adiacen din fiier. Funcia
componenete() se folosete pentru a afia componentele tare conexe ale grafului.
Programul 3
#include<fstream.h>
typedef stiva[100];
int a[20][20], n, k, as, ev, x, y, v[20], este1, este2, este=0;
stiva st;
fstream f (graf19.txt, ios::in);
void citeste()
void init()
int successor()
int valid()
int solutie()
{return st[k]==y;}
void tipar() {este=1;}
void bt()
void component()
{int i, j, m=0;
for(i=1; i<=n; i++)
if(v[i]==0)
{m++; v[i]=1; cout<<componenta conexa<<m<<:<<i<< ;
for (j=1; j<=n; j++)
if(j!=i)
{x=i; y=j; st[1]=x; este=0; bt(); este1=este; x=j; y=i; st[1]=x; este=0; bt() ; este2=este;
if (este1 && este2 ) {v[j]=1; cout<<j<< ;}}
cout<<endl;}}
void main() {citeste(); componente();}
Algoritmul const in eliminarea unui nod din coada de ateptare i adugarea vecinilor
(succesorilor) si n coada de ateptare.Fiecare nod va fi adugat n coada de ateptare o
dat i, prin urmare, va fi eliminat din coada de ateptare o singur dat. Complexitatea
operaiilor de eliminare a celor n noduri din coada de ateptare este O(n). Pentru a aduga
noduri la coada de ateptare, sunt examinai vecinii (succesorii) nodului curent. Vecinii
(succesorii) unui nod sunt examinai o singur dat, atunci cnd nodul este eliminat din
coada de ateptare. Numrul total de vecini examinai este egal cu m numrul de muchii
(arce) ale grafului. Complexitatea operaiilor de adugare de noduri este O(m).
Complexitatea algoritmului este liniar O(m+n).
Studiu de caz
Scop: exemplificarea unei aplicaii n care pentru reprezentarea datelor se folosete un
graf ponderat.
Exemplul 1. O firm deine depozite de marf n mai multe localiti. O reea de osele
leag direct unele dintre aceste localitti. Distana dintre dou localiti este msurat n
kilometri. S se determine traseul pe care s-l parcurg o main pentru a transporta
marfa de la depozitul din oraul A la depozitul din oraul B astfel nct distana parcurs
n kilometri s fie minim.
Localitile formeaz nodurile unui graf neorientat n care fiecare muchie reprezint o
legatur direct pe osea ntre dou localiti. Fiecare muchie are asociat o mrime
distana . Aceast mrime este costul muchiei, iar graful este un graf ponderat. Cerina
problemei este de a determina un drum cu lungime minima (cu costul minim) ntre dou
noduri ale grafului.
Exemplul 2. O persoan trebuie s se deplaseze cu autoturismul ct mai repede ntre dou
intersecii din ora. Traficul ntre dou intersecii nu este ntotdeauna n ambele sensuri.
Cunoscnd timpul mediu de deplasare ntre dou intersecii, s se determine care este
traseul pe care trebuie s-l aleag pentru a ajunge de la intersecia A la intersecia B ct
mai repede.
Interseciile formeaz nodurile unui graf orientat n care fiecare arc reprezint sensul de
circulaie peo strad care leag direct dou intersecii. Fiecare arc are asociat o mrime
timpul mediu de parcurgere. Aceast mrime este costul muchiei, iar graful este un graf
ponderat. Cerina problemei este de a determina un drum cu timpul de parcurgere minim
(cu costul minim) ntre dou noduri ale grafului.
a) Matricea costurilor minime. Elementele ai,j ale matricei sunt definite astfel:
c, daca exist o muchie (un arc) cu costul c>0 ntre nodurile i i j, cu ij
ai,j= 0, dac i=j
, dac nu exist o muchie (un arc) ntre nodurile i i j, cu ij
Fiecrei muchii (arc) care nu exist n graf i se asociaz o valoare foarte mare, deoarece,
cutndu-se costul minim, aceast muchie (arc) nu va mai fi selectat. Deoarece pentru
implementarea matricei nu se poate folosi simbolul , n locul lui se va folosi cea mai
mare valoare care se poate reprezenta n calculator pentru tipul de dat asociat costului.
Exemplu. Pentru graful ponderat G27 din figura 32 matricea costurilor minime este
prezentat alturat.
1
2
3
4
5
1
0
2
4
0
3
3
0
4
0
2
b) Matricea costurilor maxime. Elementele ai,j ale matricei sunt definite astfel:
c, dac exist o muchie (un arc) cu costul c>0 ntre nodurile i i j, cu ij
ai,j
0, dac i=j
-, dac nu exist o muchie (un arc) ntre nodurile i i j, cu ij
Fiecrei muchii (arc) care nu exist in graf i se asociaz o valoare foarte mic, deoarece,
cutndu-se costul maxim, aceast muchie (arc) nu va mai fi selectat. Deoarece pentru
implementarea matricei nu se poate folosi simbolul -, n locul lui se va folosi cea mai
mic valoare ce se poate reprezenta n calculator pentru tipul de dat asociat costului.
Algoritmul pentru crearea matricei costurilor
Pentru a crea matricea costurilor trebuie s se citeasc pentru fiecare muchie (arc)
nodurile de la extremiti i costul asociat fiecrei muchii (arc). Aceste informaii se pot
citi de la tastatur sau dintr-un fiier. Algoritmul pentru crearea matricei costurilor este:
PAS1. Se iniializeaz matricea astfel: toate elementele de pe diagonala principal cu
valoarea 0, iar restul elementelor cu valoarea corespunztoare pentru (-).
PAS2. Se actualizeaz matricea cu informaiile despre costurile asociate muchiilor
(arcelor) astfel: pentru fiecare muchie (arc) [i,j] cu costul c, elementului a[i][j] i se va
atribui valoarea costului c.
Implementarea algoritmului pentru matricea costurilor minime a unui graf orientat.
Pentru iniializarea matricei costurilor se folosete funcia init(), iar pentru actualizarea ei
funcia citire(). Elementele matricei fiind de tip int nu se poate folosi pentru simbolul
constanta de sistem MAXINT, deoarece n algoritmii de determinare a drumului cu costul
minim prin adunrile repetate ale elementelor matricei (care pot avea i valoarea
MAXINT) se depete capacitatea de reprezentare a tipului int. Exist dou soluii:
-Pentru elementele matricei se alege tipul long, chiar dac acest tip de dat nu este
justificat de valorile foarte mici ale costurilor (i se obine o utilizare ineficient a
memoriei interne)
-Se definete o constant cu o valoare foarte mare n comparaie cu celelalte costuri.
n implementarea algoritmului n programul 1 s-a ales varianta unei constante definite
MAX. datele se citesc din fiierul text cost.txt, n care pe prima linie exist un numr care
reprezint numrul de noduri ale grafului, iar pe urmtoarele rnduri cte trei valori
numerice separate prin spaiu, care reprezint nodurile de la extremitatea unui arc i i j
i costul asociat unui arc c.
Programul 1
#include <fstream.h>
int a[100][100], n;
int const MAX=5000;
fstream f (cost.txt , ios :: in);
void init()
//se initializeaza matricea costurilor
{int i,j; f>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) if (i==j) a[i][j]=0;
else a[i][j]=MAX ;}
void citire() //se actualizeaza matricea costurilor cu date din fisier
{int i, j, c;
k=1
1
2
3
4
5
k=2
1
0
2
4
0
5
3
3
0
4
5
0
2
0
k=3
1
0
1
2
3
4
5
1
2
3
4
5
1
0
2
4
0
5
3
3
0
4
5
4
11
7
12
0
2
5
12
8
13
1
2
3
4
5
1
0
2
4
0
5
k=4
1
2
3
4
5
1
0
2
4
0
5
3
3
11
0
4
5
4
11
7
12
0
2
5
12
8
13
17
0
2
4
0
5
3
3
0
4
5
3
3
11
0
4
5
4
11
7
12
0
2
4
11
7
12
0
2
5
12
8
13
17
0
5
12
8
13
17
0
k=5
Interpretarea datelor din matricea obinut n urma transformrilor se face astfel: drumul
de la nodul i la nodul j are costul minim a[i][j]. De exemplu, drumul cu costul minim de
la nodul 2 la nodul 4 are costul minim 7. Matricea nu furnizeaz informaii despre
etichetele drumului cu costul minim.
Pentru implementarea algoritmului se folosesc subprogramele:
funcia procedural init iniializeaz matricea costurilor;
funcia procedural citire actualizeaz matricea costurilor cu datele din fiier;
funcia procedural transformare transform matricea costurilor;
funcia procedural afisare afieaza lungimea drumurilor minime ntre toate
nodurile grafului.
Implementarea algoritmului se realizeaz cu programul urmtor:
Programul 2
#include <fstream.h>
int a[100][100], n;
int const MAX=5000;
fstream f("cost.txt", ios::in);
void init()
{//se initializeaza matricea costurilor}
void citire() {//se actualizeaza matricea costurilor cu datele din fisier}
void transformare() //se transforma matricea costurilor
{for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];}
void afisare()
{cout<<"costul drumurilor minime intre nodurile: "<<endl;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (a[i][j]<MAX && i!=j) cout<<"("<<i<<","<<j<<")-"<<a[i][j]<<endl;}
void main()
Drumul cu costul cel mai mic este cu nodul 3: d[3]=3. Nodul 3 se va extrage din coada Q.
Se analizeaz nodurile care rmn n coada de prioriti:
Nodul 2. d[3]+a[3][2] = 3+5=8>4. Nu se modific nimic.
Nodul 4. d[3]+a[3][4] = 3+=>4. Nu se modific nimic.
Nodul 5. d[3]+a[3][5] = 3+=>4. Nu se modific nimic.
Vectorii
s
d
p
1
1
0
0
2
0
4
1
3
1
3
1
4
0
5
0
Drumul cu costul cel mai mic este cu nodul 2: d[2]=4. Nodul 2 se va extrage din coada Q.
Se analizeaz nodurile care rmn n coada de prioriti:
Nodul 4. d[2]+a[2][4] = 4+7=11<. Se modifica: d[4] = 11 si p[4] = 2.
Nodul 5. d[2]+a[2][5] = 4+8=12<. Se modifica: d[5] = 12 si p[5] = 2.
Vectorii
s
d
p
1
1
0
0
2
1
4
1
3
1
3
1
4
0
11
2
5
0
12
2
Drumul cu costul cel mai mic este cu nodul 4: d[4]=11. Nodul 4 se va extrage din coada
Q. Se analizeaz nodurile care rmn n coada de prioriti:
Nodul 5. d[4]+a[4][5] = 11+=>12. Nu se modific nimic.
Vectorii
s
d
p
1
1
0
0
2
1
4
1
3
1
3
1
4
1
11
2
5
0
12
2
Drumul cu costul cel mai mic este cu nodul 5: d[5]=15. Nodul 5 se va extrage din coada
Q. Coada este vid i se termin execuia algoritmului.
Final:
Vectorii
1
2
3
4
5
s
1
1
1
1
1
d
0
4
3
11
12
p
0
1
1
2
2
Din datele care se regsesc n vectorii d i p la terminarea algoritmului se obin
urmtoarele informaii:
o d[i] reprezint costul minim al drumului de la nodul x la nodul i. De exemplu,
pentru nodul 4 costul minim este 11.
I.6.Grafuri speciale
I.6.1. Graf nul.Graf complet.Graf parial.Subgraf
Graful nul
Graful G=(X,U) se numete graf nul dac mulimea U este vid (U=), adic graful nu
are muchii. Reprezentarea sa se face prin noduri izolate.
Exemplul 1: Graful N=(X,V) unde mulimea X={1,2,3,4} este mulimea nodurilor, iar
mulimea V= este mulimea muchiilor este un graf nul ( graful are noduri dar nu are
muchii).
1
Matricea de adiacen a unui graf nul este matricea zero ( nu conine nici un element cu
valoarea 1).
Graful complet
Un graf cu n noduri este un graf complet dac are proprietatea c, oricare ar fi dou
noduri ale grafului, ele sunt adiacente. El se noteaz cu Kn.
Exemplul 2:
1
Se poate construi un singur graf neorientat complet, cu n noduri, deoarece ntre dou
noduri, x i y, exist o singur muchie [x,y].
Numrul m de muchii ale unui graf neorientat complet, cu n noduri Kn. este:
m=n(n-1)/2.
Numrul de grafuri orientate complete care se pot construi cu n noduri este egal cu
nk=3C22.
n cazul matricei de adiacen a unui graf neorientat complet, valoarea fiecrui element
care nu se gsete pe diagonala principal este 1.
n cazul matricei de adiacen a unui graf orientat complet- pentru orice pereche de
noduri i i j, diferite ntre ele (ij)- a[i][j]=1 sau a[j][i]=1.
Numrul minim de arce ntr-un graf orientat complet cu n noduri este egal cu numrul de
muchii ale grafului neorientat complet Kn.
Numrul maxim de arce ntr-un graf orientat complet cu n noduri este egal cu dublul
numrului de muchii ale grafului neorientat complet Kn.
Algoritmi pentru prelucrarea grafurilor complete
1.Algoritm pentru a determina numrul minim de arce care trebuie adugate la un graf
orientat, pentru a obine un graf orientat complet.
Algoritmul. Se numr perechile de noduri i i j (ij) ntre care nu exist nici un arc.
Implementarea algoritmului. n programul 1, informaiile despre graful orientat se citesc
din fiierul text gc.txt: de pe prima linie numrul de noduri, i apoi, de pe urmtoarele
rnduri matricea de adiacen.
Programul 1
#include<iostream.h>
int n,a[10][10];
fstream f(gc.txt,ios::in);
void citeste() {//se citeste matricea de adiacenta din fisier}
void main()
{int i,j,m=0; citeste();
for(i=2;i<=n;i++) if(a[i][j]==0 && a[j][i]==0) m++;
cout<<Numarul de arce care trebuie adaugate este <<m;}
2.Algoritmul pentru a determina numrul maxim de noduri izolate pe care poate s le
conin un graf neorientat care are n noduri i m muchii.
Algoritmul. Se identific graful complet care se pote forma astfel nct s consume ct
mai multe muchii(mmax) din cele m muchii ale grafului(mmax<=m). Graful complet
astfel obinut are n1 noduri: mmax= n1[(n1-1)/2]<=m. Numrul de noduri n1 este partea
ntreag din rdcina pozitiv a ecuaiei de gradul II: n1=[(1+1+8xm)/2]. Pentru
diferena de muchii rmase(m-mmax) mai este necesar un nod, pentru a lega aceste
muchii de nodurile grafului complet care s-a format. Numrul de noduri izolate este: nn1-1.
Programul 2
#include<iostream.h>
#include<math.h>
void main()
{int m,n,n1; cout<<muchii= ; cin>>m; cout<<noduri ; cin>>n;
n1=(int)((1+sqrt(1+8*m))/2);
cout<<Numarul maxim de noduri izolate este <<n-n1-1;}
Graful parial
Fie graful G=(X,U) i multimea V. Graful Gp=(X,V) se numete graf parial al grafului
G.
Astfel spus, un graf parial al grafului G este el nsui sau un graf care s-a obinut prin
eliminarea unor muchii(arce) din graful G.
Numrul de grafuri pariale ale unui graf cu m muchii(arce) este egal cu 2m.
Algoritmi pentru prelucrarea grafurilor pariale
1.Generarea tuturor grafurilor pariale ale unui graf neorientat.
Algoritmul. Se folosete metoda backtracking. n stiv se vor genera muchiile grafului
parial. Deoarece graful parial poate avea p muchii(0<=p<=m), se va apela repetat
subprogramul bt(), la fiecare apel generndu-se variantele cu p muchii. Fiecare apel al
subprogramului bt() trebuie s genereze Cpn de muchii(arce) din graf. La fiecare apel al
subprogramului, soluia se obine atunci cnd n stiv s-au generat cele p muchii ale
grafului parial. Evidena muchiilor este pstrat n matricea de inciden.
Implementarea algoritmului. Se realizeaz cu programul 3.Se citete din fiierul text
graf15.txt matricea de adiacen a unui graf neorientat. Pentru fiecare graf parial se
afieaz muchiile. Matricea de inciden b se obine din matricea de adiacen cu funcia
transformare(). n variabila nr se contorizeaz numrul de grafuri pariale generate. n
funcia tipar() se afieaz graful parial generat.
Programul 3
#include<iostream.h>
fstream f(graf13.txt,ios::in);
typedef int stiva[100];
int n,m,p,k,ev,as,a[10][10], b[10][20], nr;
stiva st;
void citeste()
{int i,j; f1>>n>>x;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) {f1>>a[i][j]; if(a[i][j]==1) m++;}
m=m/2; f.close();}
void transformare()
{int i,j,k=1;
for (i=1;i<=n;i++)
for(j=1;j<=n;j++) if(a[i][j]==1) {b[i][k]=1; b[j][k]=1; k++;}}
void init() {st[k]=0;}
int succesor()
{if( st[k]<m) {st[k]=st[k]+1; return 1; } else return 0; }
int valid()
{if(k<1 && st[k]<st[k-1]) return0;
for(int i=1;i<k;i++) if(st[k]==st[i]) return 0; return 1; }
int solutie() {return k==p;}
void tipar()
{int i, j; nr++;
cout<<:Graful partial <<nr<<endl; cout<<Muchiile: ;
for(i=1;i<=p;i++)
{for(j=1;j<=n;j++) if (b[j][st[i]]==1) cout<<j<< ; cout<<; ; }
void bt() {//partea fixa a algoritmului backtracking}
void main()
{citeste(); transformare();
for(p=m;p>=0;p- -) bt() ; }
etichete de noduri desprite prin spaiu. Cerina este s se obin subgraful prin
eliminarea tuturor muchiilor care au la extremiti un nod cu grad par i nodul x. n
vectorul v se memoreaz nodurile care au grad par. n programul 5, funcia citeste() se
folosete pentru a citi informaiile despre matricea de adiacen a grafului din fiierul
text, funcia scrie() pentru a scrie n fiierul text informaiile despre lista muchiilor
grafului parial, funcia grad() pentru a determina gradul unui nod, iar funcia
graf_partial() pentru a obine graful parial. Pentru a obine graful parial, se caut toate
muchiile care au la extremiti un nod cu gradul par i nodul x(muchiile [v[i],x] pentru
care a[v[i]][x]==1) i se elimin aceste muchii.
Programul 5
#include<iostream.h>
fstream f1(g3p.txt,ios::in), f2(g4p.txt,ios::out);
int a[20][20],n,m,x,v[10];
void citeste() {//se citeste matricea de adiacenta din fisier}
int grad(int i)
{int j,g=0; for(j=1;j<=n;j++) g+=a[i][j]; return g;}
void graf_partia()
{int i,k=0; for(i=1;i<=n;i++)
if(grad(i)%2==0) {k++; v[k]=i; }
if( a[v[i]][x]==1) {a[v[i]][x]=0; a[x][v[i]]=0; m--; }}
void scrie()
{int i,j; f2<<n<< <<m<<endl;
for(i=1;i<=n;i++)
for(j=1;j<i;j++) if(a[i][j]==1) f2<<i<< <<j<<endl;
f2.close(); }
void main() {citeste(); graf_partial(); scrie();}
Subgraful
Fie graful G=(X,U).Graful Gs=(Y,V) se numeste subgraf al grafului G dac Y
X(subgraful conine numai noduri ale grafului) i muchiile (arcele) din mulimea V sunt
toate muchiile(arcele) din mulimea U care au ambele extremiti n mulimea de noduri
Y.Se spune c subgraful Gs este indus sau generat de mulimea de noduri Y.
Un subgraf al grafului G este el nsui sau un graf care s-a obinut prin suprimarea din
graful G a unor noduri i a tuturor muchiilor(arcelor) incidente cu aceste noduri.
Exemple:
1.Pentru graful neorientat G1=(X1,U1),definit anterior,graful G1s =(Y1 V1),definit astfel:
-mulimea nodurilor este Y1={1,2,3,5,6,7}.
-mulimea muchiilor este V1={[1,2],[1,3],[2,5],[6,7]}.
este subgraf al grafului G1.
Graful G1
Graful G1s
-1.
return 1;}
int soluie() {return k==p; }
void tipar()
{int i,j; nr++;
cout<<Subgraful <<nr<<endl<<Nodurile: ;
for(i=1;i<=p;i++) cout <<st[i]<< ; cout<<endl;
cout<<Muchiile: ; // cout<<Arcele: ; pentru graful orientat
for (i=1;i<=p;i++)
for (j=i+1; j<=p;j++) //for (j=1;j<=p;j++) pentru graful orientat
if (a[st[i]] [st[j]]==1) cout<<st[i]<<-<<st[j]<< ;
cout<<endl;}
void bt() {//partea fixa a algoritmului backtracking}
void main()
{citeste (); for(p=n;p>=1;p--) bt();}
2.Verificarea dac un graf Gs este un subgraf al unu graf G.
Algoritmul.Se verific dac:
-numrul de noduri din graful Gs este mai mic sau cel mult egal cu numrul de noduri din
graful G;
-etichetele nodurilor din graful Gs exist printre etichetele grafului G;
-ntre nodurile din graful Gs exista muchiile dintre nodurile din graful G i numai acelea.
Implementarea algoritmului.Se folosete programul 2.Se citesc,din dou fiiere text
g1s.txt i g2s.txt,informaii despre dou grafuri neorientate(orientate):de pe prima linie
numrul de noduri i apoi de pe urmtoarele rnduri,matricea de adiacen.n fiierul
g2s.txt pe ultimul rnd,dupa matricea de adiacen,este memorat un ir de numere care
reprezint etichetele nodurilor din acest graf.Matricele de adiacen ale celor dou grafuri
sunt a1 i a2,cu dimensiunea n,respectiv m.n vectorul v se memoreaz etichetele
nodurilor celui de al doilea graf.Funcia subgraf() verific dac graful Gs este subgraf al
grafului G.
Programul 2
#include<iostream.h>
int m,n,a1[10][10],a2[10][10],v[10];
fstream f1(g1s.txt,ios::in), f2(g2s.txt,ios::in);
int subgraf()
{if (m>n) return 0;
else { for (int i=1;i<=m;i++) if (v[i]>n) return 0;
for (int i=1;i<=m;i++)
for (int j=1;j<=m;j++) if (a2[i][j]!=a1[v[i]] [v[j]]) return 0;}
return 1;}
void main()
{int i,j; f1>>n;
for(i=1;i<=n;i++)
for (j=1;j<=n;j++) f1>>a1[i][j]; f1.close();
f2>>m;
for (i=1;i<=m;i++)
for(j=1;j<=m;j++) f2>>a2[i][j];
int tipar()
{int i,j; zero();
if (x==0)
{for (i=1;i<=p;i++)
for(j=1;j<=p;j++) if (a1[st[i]] [st[j]]==1) b[i][j]=1;
for (i=1;i<=p;i++)
for (j=1;j<=p;j++) if (a2[i][j]!=b[i][j]) return 0;}
else
{ for (i=1;i<=p;i++)
for(j=1;j,=p;j++) if (a2 [st[i][j]] [st[i][j]]==1) b[i][j]=1;
for (i=1;i<=p;i++)
for (j=1;j<=p;j++) if (a1[i][j]!=b[i][j] ) return 0;}
return 1;}
void bt()
void main()
{int i,j,m; f1>>n;
for (i=1;i<=n;i++)
for (j=1;j<=p;j++) f1>>a1[i][j]; f1.close();
f2>>p;
for (i=1;i<=p;i++)
for(j=1;j<=p;j++) f2>>a2[i][j]; f2.close();
if (p>n) {m=n; n=p; n=m; x=1;}else x=0;
bt();
if (gasit) if (x) cout<<prima matrice de adiacen este a subgrafului;
else cout<<a doua matrice de adiacen este a subgrafului;
else cout <<nu este subgraf ;}
I.6.2.Graf bipartit
Graful G=(X,U) se numete bipartit dac exis dou mulimi nevide de noduri A i B
care au urmtoarele proprieti: AUB=X i AB= i orice muchie (arc) din mulimea U
are o extremitate n mulimea de noduri A i o alt extremitate n mulimea de noduri B.
Exemple:
1.Graful neorientat definit n figura 35, este un graf bipartit, deoarece exist mulimile A
i B care s ndeplineasc condiiile din definiie: A={1, 3, 6, 7, 8, 10} i B={2, 4, 5, 9,
11}.Se observ c: AUB= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}= X i AB= i c fiecare
muchie u din
U ={[1,2], [1,4], [2,3], [3,4], [3,5], [5,6], [5,7], [5,8], [7,9]} are o extremitate n mulimea
A i cealalt extremitate n mulimea B:
Fig.35
Graful bipartit G=(X,U) se numete graf bipartit complet dac pentru orice nod xi A i
orice nod xj B exist o muchie (un arc) format din cele dou noduri care aparine
mulimii U: [xi, xj] U.
Exemple:
1.Graful neorientat G28 = (X28,U28) din figura 36, definit astfel: X28={1, 2, 3, 4} i U28=
{[1,2], [1,4], [2,3], [2,4]} este un graf bipartit complet deoarece exist mulimile A i B
care ndeplinesc condiiile din definiie: A={1, 3} i B= {2, 4}. Se observ c: AUB= {1,
2, 3, 4} i AB= i c fiecare nod din mulimea A este legat cu o muchie de fiecare nod
din mulimea B.
Fig.36-Graful G28
2.Graful orientat G29= (X29,U29) definit astfel: X29 ={1, 2, 3, 4} i U29={[1,2], [1,4], [2,1],
[2,3], [3,2], [4,3]} este un graf bipartit complet , deoarece exist mulimile A i B care s
ndeplineasc condiiile din definiie: A= {1, 3} si B= {2, 4}.Se observ c: AUB= {1, 2,
3, 4} i AB = i c fiecare nod din mulimea A este legat cu cel puin un arc de fiecare
nod din mulimea B.
Fig.37-Graful G29
Implementarea algoritmului. Se citesc din fiierul text gb.txt informaii despre un graf
neorientat (numrul de noduri i matricea de adiacen). Funcia bipartit ( ) verific dac
graful este bipartit furniznd un rezultat logic. Elementele vectorului x n care se
genereaz mulimile A i B sunt iniial 0. Variabila gasit se folosete pentru a verifica
dac s-au gasit cele dou mulimi de noduri corespunztoare unui graf bipartit (are
valoarea 1 true, atunci cnd s-au gsit).
Programul 2
#include<fstream.h>
#include<math.h>
fstream f (gb.txt ,ios::in);
int a[10] [10], n;
void citeste ( ) {//citete matricea de adiacen din fiier}
int bipartit ( )
{int x[10]={0}, i, j, m, k=0, posibil=1, gasit=0;
while (posibil && !gasit)
{m=n;
while (m>0 && x[m]==1) {x[m]=0; m --;}
if (m==0) posibil=0;
else
{x[m]=1; k++;
if (k<=pow (2,n) 2)
for (i=1, gasit=1;i<=n && gasit; i++)
for (j=1; j<=n && gasit; j++)
if (a[i] [j]==1)
if (x[i]==1 && x[j]==1)| |(x[i]==0 && x[j]==0)) gasit=0; }}
return gasit; }
void main ( )
{citeste ( );
if (bipartit ( ) ) cout<<este bipartit ;
else cout<<nu este bipartit;}
Varianta 2. Elementele mulimilor A i B se genereaz separat, n doi vectori. Pentru
generarea mulimii A se folosete metoda backtracking (etichetele nodurilor mulimii A se
genereaz n stiv. Funcia bt ( ) este apelat de n-1 ori pentru a genera n stiv cele p
elemente ale multimii (1pn-1). Multimea B este format din nodurile grafului care nu
se gsesc n mulimea A.
Implementarea algoritmului. Matricea A este matricea de adiacen a grafului, iar n
vectorii a i b se genereaz elementele mulimilor A i B. n funcia tipar ( ) se copiaz
coninutul stivei n vectorul a i se scriu n vectorul b etichetele nodurilor care nu sunt n
vectorul a. Pentru a identifica etichetele nodurilor care nu sunt n vectorul a se folosete
variabila logic gasit. Tot n aceast funcie se verific dac aceste mulimi corespund
unui graf bipartit, astfel: se verific, pentru toate elementele celor doi vectori, daca
muchiile generate cu un nod din vectorul a i un nod din vectorul b sunt muchii n graf.
n caz afirmativ, se verific dac muchiile astfel generate sunt toate muchiile grafului.
Variabila nr se folosete pentru a numra muchiile formate cu nodurile din cei doi
vectori, iar variabila logic este pentru a verifica dac graful este bipartit (are vaolarea 1true, dac numrul de muchii gsite este egal cu numrul total de muchii ale grafului m).
#include<fstream.h>
frstream f (gb.txt ,ios::in) ;
typedef int stiva [100];
int n, k, ev, as, A[10] [10], b[10], a[10], m, este, p;
stiva st;
void citeste ( )
{int i, j; f>>n;
for (i=1; i<=n; i++;
for(j=1; j<=n; j++) {f>>A[i] [j]; m=m+ A[i] [j];} f.close ( ); m=m/2;}
void init ( ) {st[k]=0; }
int successor ( )
{ if (st[k]<n) {st[k]=st[k]+1; return 1;} else return 0;}
int valid ( )
{if (k>1 && st[k]<st[k-1]) return 0;
for (int i=1; i<k; i++) if (st[k]==st[i]) return 0; return 1;}
int solutie( ) {return k==p;}
void tipar ( )
{int i, j, q=0, gasit, nr=0;
for (int i=1; i<=p; i++) a[i]=st[i];
for (i=1; i<=n; i++)
{for (j=1, gasit=0; j<=p && !gasit; j++) if(a[j]==i) gasit=1;
if (!gasit) {q++; b[q]=i; }}
for (i=1; i<=p; i++)
for (j=1; j<=q; j++)
if (A[a [i] ] [b [j] ]==1) nr++;
if (nr==m) este=1; }
void bt ( ) {// partea fix a algoritmului backtracking}
void main( ) {citeste ( );
for (p=1; p<= n-1 && !este; p++) bt ( );
if (este) cout<<este bipartit;
else cout<<nu este bipartit; }
Fig.39
Orice problem la care soluia este de a gsi un traseu- care pornete dintr-un anumit
punct, trebuie s treac prin puncte precizate, cu revenire la punctul de pornire- se rezolv
prin gsirea unui ciclu hamiltonian.
De exemplu:
firm de mesagerie trebuie s distribuie zilnic colete la mai multe adrese.Maina
care distribuie aceste colete pleac de la sediul firmei, ajunce la mai multe puncte
din ora i revine la sediul firmei.Legtura direct dintre dou puncte este
caracterizat prin distana msurat n kilometri (costul asociat fiecrei muchii).
Trebuie s se gseasc traseul de lungime minim pe care trebuie s-l parcurg
maina.
persoan dorete s fac un circuit prin ar i s viziteze mai multe puncte
turistice, plecnd din localitatea de domiciliu i ntorcndu-se n aceeai localitate.
Legtura direct dintre dou puncte turistice este caracterizat prin distana
msurat n kilometri (costul asociat unei muchii). Trebuie s se gseasc circuitul
turistic de lungime minim.
persoan dorete s viziteze mai multe cabane,ntorcndu-se la locul de plecare.
Legtura direct dintre dou cabane este caracterizat prin timpul necesar
parcurgerii traseului de munte (costul asociat fiecrei muchii). Trebuie s se
gseasc circuitul de vizitare a cabanelor care s se fac n timp minim.
Dac graful G=(X,U) este un graf cu mai mult de dou noduri (n>=3) i gradul fiecrui
nod x X satisface condiia d(x)>=n/2, atunci graful G este hamiltonian.
Algoritm pentru parcurgerea unui graf hamiltonian
Algoritmul.Pentru a determina dac un graf este hamiltonian se verific dac exist un
ciclu hamiltonian.Este suficient s se caute lanurile elementare care pornesc din nodul
cu eticheta 1 i se nchid n acest nod. Se poate folosi fie metoda backtracking, fie metoda
parcurgerii n lime a grafului. Prin aceste metode se pot determina i toate ciclurile
hamiltoniene, dac exist, astfel: se caut toate ciclurile elementare care, pornind dintr-un
nod, parcurg toate celelalte noduri ale grafului i se nchid printr-o muchie cu nodul de
pornire.
PAS2.Se verific dac graful este eulerian, adic dac ndeplinete condiia s nu aiba
noduri izolate nodurile s aib grade pare i s fie conex.
PAS3.Dac graful nu este eulerian atunci se afieaz mesajul Graful nu este eulerian i
se termin algoritmul ; astfel se scrie mesajul Graful este eulerian i se
trece la pasul 4 pentru a determina un ciclu eulerian.
PAS4.Se pleac dintr-un nod oarecare.
PAS5.Execut urmtorii pai pentru a construi n vectorul c un prim ciclu prin
parcurgerea din aproape n aproape a muchiilor grafului, pornind de la
nodul cu eticheta j egal cu 1:j=1
PAS6. Ct timp nu s-a gsit o muchie ntre nodul curent k din coada c (c[k]) i un
alt nod j din graf (j<=n) execut:
PAS7. Dac exist o muchie ntre nodul k din coada c (c[k]) i un alt nod j din
graf (a[c[k]][j]==1), atunci se trece la pasul 8 ; altfel se trece la pasul 11.
PAS8. Se adaug nodul j la coada c (k=k+1;c[k]=j).
PAS9. Se micoreaz cu o unitate gradul celor dou noduri parcurse (g[i]--;
g[c[k-1]]--;).
PAS10. Se terge din matricea de adiacen muchia parcurs (a[c[k]][j]=0;
a[j][c[k]]=0;).
PAS11. Se trece la urmtorul nod prin incrementarea lui j (j=j+1) i se revine la
pasul 6.
Pn cnd nodul curent din coada c (c[k]) este diferit de nodul de pornire.
PAS12.Ct timp mai exista muchii care nu au fost incluse in ciclu (k-1<m)execut:
PAS13. Se caut n coada c un nod i de plecare pentru ciclul c1 adic un nod
pentru care s mai existe muchii incidente cu el care nu au fost parcurse
(grad[c[i]]>0).
PAS14. Se iniializeaz cu acest nod ciclul c1 (c1[1]=c[i]) i se memoreaz acest
nod n variabila q.
PAS15. Se construiete un nou ciclu parcurgnd din algoritm pentru coada c1 de
la pasul 5 pn la pasul11.Acest ciclu va avea p elemente .
PAS16.Se concateneaz ciclul c1 cu ciclul c astfel: mai ntai se deplaseaz elementele din
vectorul c ncepnd cu pozitia q cu p poziii spre dreapta dup care se
intercaleaz ntre poziia q i poziia q+p elementele vectorului c1.
PAS17.Se afieaz elementele vectorului c.
Programul 1
#include<fstream.h>
typedef stiva[20];
int n,a[20][20],vizitat[20],vf,k,m,g[20],p=1,c[20],v1[20];
stiva st;
fstream f(graf_e.txt,ios::in);
void citeste() {//se citeste matricea de adiacenta}
void init(int i) {vf=1; st[vf]=i;vizitat[i]=1}
int este_vida() {vf++; st[vf]=i; vizitat[i]=1}
void elimin(0 {vf--;}
void prelucrare()
{int i=1; k=st[vf];
while(i<=n && (a[i][k]==0 || (a[i][k]==1 && vizitat [i]==1))) i++;
Orice graf turneu conine un drum elementar care trece prin toate nodurile grafului.
Pentru orice nod xi dintr-un graf turneu cu n noduri , d+(xi)+d-(xi)=n-1.
Studiu de caz
Scop:exemplificarea unei aplicaii n care soluia problemei este un graf turneu.
Enunul problemei : Pentru un concurs hipic s-au montat n obstacole . Pentru a parcurge
traseul concursului, clreii pot ncepe cu orice obstacol , trebuie s treac peste toate
obstacolele , iar de la un obstacol la altul pot circula ntr-un singur sens , stabilit inaintea
concursului. S se precizeze ce trasee poate urma un clre.
Obstacolele formeaza nodurile unui graf orientat , n care fiecare dou noduri sunt legate
de un arc.Deoarece drumul dintre dou obstacole nu poate fi parcurs dect ntr-un singur
sens,nseamn c graful concursului este un graf turneu.A determina un traseu pentru
parcurgerea obstacolelor , nseamn a determina n graful turneu un drum elementar ca
trece prin toate nodurile grafului.
Algoritmul pentru parcurgerea grafului turneu
Pentru a determina drumul elementar care trece prin toate nodurile grafului se poate
folosi fie metoda backtracking, fie urmtorul algoritm, prin care se extrag cele n noduri
ale drumului ntr-un vector D.n acest algoritm,se iniializeaz vectorul cu nodurile cu
etichetele 1 i 2 sau 2 i 1, n funcie de arcul care exist [1,2] respectiv[2,1], dup care se
insereaz n vectorul drumului i celelalte noduri, n funcie de arcele care exist n graf:
PAS1. Dac exist arcul[1,2], atunci D[1]=1 i D[2]=2 ; altfel , D[1]=2 i D[2]=1
PAS2. Se iniializeaz lungimea drumului,m, cu 2.
PAS3. Pentru nodurile cu eticheta i de la 3 pn la n execut:
PAS4. Dac exist arcul [i,1],atunci poziia de inserare k a nodului i este 1 i se trece la
pasul 7;altfel,pentru a parcurge nodurile din drum se iniializeaz indicele j cu valoarea 1
i se trece la Pasul 5.
PAS5. Ct timp nu s-a ajuns la captul vectorului D i nu s-a gsit poziia de inserare a
nodului i execut:
PAS6. Dac exist arcul ntre nodul cu indicele j din drum i nodul i i exist i
arcul ntre nodul i i nodul cu indicele j+1 din drum , atunci poziia de inserare k este
j+1;altfel,se trece la urmtorul nod din drum prin incrementarea variabilei j i se revine la
pasul 6.
PAS7. Se deplaseaz elementele vectorului din poziia k spre dreapta.
PAS8. Se insereaza nodul i n poziia k.
PAS9. Se incrementeaz lungimea m a drumului D i revine la pasul 3.
Implementarea algoritmului.Se realizeaz programul 2:informaiile despre graful
neorientat se gsesc n fiierul graf_t.txt pe prima linie numrul de noduri , apoi matricea
de adiacen. Nodurile drumului elementar vor fi generate n vectorul D. Se folosesc
urmtoarele funcii: citete() pentru a citi matricea de adiacen din fiier, generare()
pentru a genera vectorul D i afiare() pentru a afia drumul elementar gsit.n funcia
generare() se folosesc urmtoarele variabile locale: i-pentru eticheta nodului care se
adaug la drum,j-pentru a cuta eticheta nodului dup care se insereaz n drum nodul cu