Sunteți pe pagina 1din 25

Grafuri neorientate

1. Graf partial
Fie G=(A,B) si G1=(A1,B1).
Spunem c G1 este un graf parial al lui G dac A=A1 i B1 este inclus sau egal cu B.
Un graf parial se obine dintr-un graf, ndeprtnd o parte dintre muchiile sale i pstrnd toate
nodurile acestuia.
Exemplu 1:

Graful iniial

Da

Da

Nu (are o muchie n plus)


Da

2. Subgraful unui graf


Fie G=(A,B) i G1=(A1,B1);
A1 inclus sau egal cu A; B1 inclus sau egal cu B.
B1 = {(x,y) / oricare x,y aparine A1 dac (x,y) aparine de B => (x,y) aparine de B1}
Subgraful se obine din graful iniial selectnd o parte din nodurile sale i o parte din nodurile
adiacente cu acesta.
Exemplu 2:

Graful iniial

Nu (nu are toate muchiile)

Da
3. Graf complet
Un graf este complet dac oricare dou vrfuri distince sunt
adiacente.
Exemplu 3:

Un graf neorientat cu n noduri are n(n-1)/2 muchii.


Exist un singur graf complet neorientat cu n noduri.
Exist mai multe grafuri orientate complete cu n noduri.

4. Grafuri bipartite
Fie G=(A,B) neorientat.
G este bipartit dac exist dou mulimi, A1 i A2 astfel nct A1 A2 = i A1 U A2 = A, iar
oricare muchie (x,y) aparinnd lui B are un capt n mulimea A1 i cellalt n A2.

Exemplu 4:

Un graf bipartit este bipartit complet dac fiecare nod din mulimea A1 este adiacent cu toate
nodurile din A2 i reciproc.
Exemplu 5:

5. Grafuri conexe
Un graf este conex dac este format dintr-un singur nod sau dac ntre oricare dou noduri ale
sale exist cel puin un lan.
Exemplu 6:

Da

Probleme rezolvate

1) Sa se verifice daca un graf neorientat este complet.


#include<iostream.h>
int n,i,j,m,a[10][10];
int main()
{
cout<<"Dati nr. de vf. ";cin>>n;
cout<<"Dati elementele matricei de adiacenta"<<endl;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++)
{
cout<<"a["<<i<<"]["<<j<<"]=";
cin>>a[i][j];
a[j][i]=a[i][j];
}
// determinarea nr. de muchii
m=0;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(a[i][j]==1) m++;
m=m/2;
if(m == n * (n-1)/2)
cout<<"Graf complet";
else
cout<<"Graful nu este complet";
}

2) Sa se verifice daca o succesiune de varfuri date este ciclu pentru un graf. In caz afirmativ, sa
se stabileasca daca este ciclu elementar sau nu.

#include<iostream.h>
int n,i,j,m,a[10][10],x[50];
int main()
{
cout<<"Dati nr. de vf. ";cin>>n;
cout<<"Dati elementele matricei de adiacenta"<<endl;
for(i=1;i<=n-1;i++)
for(j=i+1;j<=n;j++){
cout<<"a["<<i<<"]["<<j<<"]=";
cin>>a[i][j];
a[j][i]=a[i][j];
}
// citirea succesiunii de vf.
cout<<"Dati nr. de muchii ";cin>>m;
for(i=1;i<=m;i++)
{
cout<<"x["<<i<<"]=";
cin>>x[i];
}
// verificare daca este lant: vf. consecutive sa fie muchii in matrice
int lant=1;
for(i=1;i<=n-1;i++)
if(a[x[i]][x[i+1]]==0) lant=0;
// primul si ultimul vf. sunt egale
int ok=1;
if(lant==1)
if(x[1]!=x[m]) ok=0;
// muchii distincte
int ciclu=1;
if(ok==1)
for(i=1;i<=m-2;i++)
for(j=i+1;j<=m;j++)
if(x[i]==x[j] && x[i+1]==x[j+1] || x[i]==x[j+1] && x[i+1]==x[j])
ciclu=0;
// verificare daca este ciclu elementar: vf. sa fie distincte doua cate doua, mai putin
primul si ultimul
if(ciclu==1 && x[1]==x[m])
cout<<"Ciclu elementar";
else
cout<<"Ciclu neelementar";
}

3) Se citesc 2 grafuri neorientate, unul cu n noduri si m muchii, iar celalalt cu k varfuri si l


muchii, ambele date prin vectorul muchiilor. Sa se determine daca al doilea graf este subgraf al
primului.
#include<fstream.h>
fstream f("date.in",ios::in);
fstream g("date2.in",ios::in);
int a[100][100],b[100][100],n,m,k,l;
int subgraf()
{for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
if(a[i][j]!=b[i][j]) return 0;
return 1;
}
int main(void)
{
int x,y,i;
f>>n>>m;
for(i=1;i<=m;i++)
{
f>>x>>y;
a[x][y]=1;
a[y][z]=1;
}
g>>k>>l;
for(i=1;i<=l;i++)
{
g>>x>>y;
b[x][y]=1;
b[y][x]=1;
}
}
if(subgraf()) cout<<"da";
else cout<<"nu";
}

4) Memorarea grafurilor neorientate folosind cele trei modalitati de reprezentare:


a) Matrice de adiacenta
b) Vector de muchii
c) Liste de vecini
#include <fstream.h>
#include <vector.h>
ifstream fin("date.in");
ofstream fout("date.out");
struct muchie
{
int i,j;
};
int A[50][50];
//
matrice de adiacenta
muchie M[1000];
//
vector muchiilor
int V1[50], V2[50]; //
liste de vecini
int n,m;
//n nr. de noduri, m nr. de muchii
void citire()
{
int x,y,i;
fin>>n>>m;
for(i=1;i<=m;i++)
{
fin>>x>>y;
M[i].i=x; M[i].j=y;
A[x][y]=A[y][x]=1;
V1[i]=x;
V2[i]=y;
}
}
void afisare()
{
int i,j;
fout<<"matricea de adiacenta:\n";
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
fout<<A[i][j]<<" ";
fout<<endl;
}
fout<<"lista muchiilor:\n";
for(i=1;i<=m;i++) fout<<M[i].i<<" "<<M[i].j<<endl;
fout<<"lista vecinilor:\n";
for(i=1;i<=n;i++)
{
8

fout<<i<<": ";
fout<<V1[i]<<","<<V2[i]<< " ";
fout<<endl;
}
fin.close();
fout.close();
}
int main()
{
citire();
afisare();
}

5) Se citeste dintr-un fisier de pe primul rand o valoare n reprezentand numarul de noduri pentru
un graf neorientat si de pe urmatoarele n linii si coloane matricea de adiacenta corespunzatoare
grafului.
a) Identificati multimea X
b) Identificati multimea U
c) Calculati gradele nodurilor impare
d) Verificati daca graful are varfuri izolate, daca da afisati nodul, daca nu afisati un mesaj
#include<iostream.h>
#include<conio.h>
#include<fstream.h>
int a[20][20];
int main()
{
ifstream f(matricegraf.in);
int n,i,j,k;
f>>n;
//a)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f>>a[i][j];
cout<<X=;
for(i=1;i<=n;i++)
cout<<i<< ;
cout<<endl;
//b)
cout<<U=;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)

if(a[i][j]==1&&i<j) cout<<(<<i<<,<<j<<);
//c)
for(i=1;i<=n;i++)
{
k=0;
for(j=1;j<=n;j++)
if(i%2==1&&a[i][j]==1) k++;
if(i%2==1) cout<<endl<<gradul nodului <<i<< este <<k<<endl;
}
//d)
for(i=1;i<=n;i++)
{
r=0;
for(j=1;j<=n;j++)
if(a[i][j]==1)
return 0;
}

6) Se citeste din fisierul graf.in de pe prima linie nr de varfuri si numarul de muchii(n,m) de pe


urmatoarele m randuri perechi de varfuri reprezentand muchiile grafului.
Se cere:
a) Sa se construiasca matricea de adiacenta si sa se scrie aceasta in fisierul MAT.OUT
b) calculati gradul fiecarui nod si pastrati acest grad intr-un vector
c) verificati daca graful are varfuri izolate
#include<iostream.h>
#include<conio.h>
#include<fstream.h>
int a[20][20],v[40];
int main()
{
ofstream g(mat.out);
ifstream f(graf.in);
int j,i,n,m,h,r=0,x,y,ok=0;
f>>n;
f>>m;
// a)
for(i=1;i<=m;i++)
{
f>>x;
f>>y;
a[x][y]=a[y][x]=1;
}
for(i=1;i<=n;i++)
{

10

for(j=1;j<=n;j++)
g<<a[i][j]<< ;
g<<endl;
}
//b)
for(i=1;i<=n;i++)
{
h=0;
for(j=1;j<=n;j++)
if(a[i][j]==1) h++;
r++;
v[r]=h;
}
for(i=1;i<=n;i++)
cout<<nodul <<i<<are rangul <<v[i]<<endl;
// c)
for(i=1;i<=n;i++)
if(v[i]==0) ok=0;
else ok=1;
if(ok==0) cout<<Graful are varfuri izolate<< ;
else cout<<Graful nu are varfuri izolate<< ;
}

7) Din fisierul GRAF.TXT, cititi de pe primul rand nr de noduri si nr de muchii, si de pe


urmatoarele m randuri perechiile de noduri reprezentand muchiile. Formati matricea de
adiacenta. enumerati nodurile terminale,
nodurile intermediare
#include<iostream.h>
#include<conio.h>
#include<fstream.h>
int a[20][20];
int main()
{
int i,j,n,m,x,y,k;
ifstream f(graf.txt);
f>>n;
f>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
f>>x; f>>y;
a[x][y]=1;
a[y][x]=1;}
for(i=1;i<=n;i++)
{

11

for(j=1;j<=n;j++)
cout<<a[i][j]<< ;
cout<<endl;
}
for(i=1;i<=n;i++)
{
k=0;
for(j=1;j<=n;j++)
if(a[i][j]==1) k++;
if(k==1) cout<<Nod terminal =<<i<<endl;
if(k>1) cout<<Nod intermediar= <<i<<endl;
}
}

Probleme propuse spre rezolvare

1. S se ruleze programele prezentate mai sus, urmrind apelurile i valorile parametrilor de apel.
2. Se citeste un graf de la tastatura: numarul de noduri, numarul de muchii si muchiile.
a) sa se afiseze matricea de adiacente
b) Sa se determine gradul unui nod citit
c) Sa se afiseze pentru un nod citit nodurile adiacente
d) sa se afiseze nodurile incidente cu cea de a x muchie din matrice
e) sa se afiseze pentru fiecare nod gradul
f) sa se afiseze nodul (nodurile) avand cei mai multi vecini
g) sa se afiseze nodurile izolate
3. Sa se determine daca o matrice citita de la tastatura poate fi matricea unui graf neorientat. In
caz afirmativ se va determina cate muchii are graful.
4. Sa se faca un program de numarare a gradelor fiecarui vrf dintr-un graf. Sa se determine apoi:
a) daca exista vrfuri izolate si vrfuri terminale;
b) toate vrfurile de grad maxim.
5. Sa se determine toate grafurile partiale ale unui graf.
6. Doua grafuri G=(X,U) si H=(Y,V) se numesc izomorfe daca exista o bijectie f: XY

12

astfel nct [x,y]U daca si numai daca [f(x),f(y)] V. Deci doua grafuri izomorfe au acelasi
numar de vrfuri si se obtin unul din celalalt printr-o renumerotare a vrfurilor. Sa se faca un
program care sa verifice daca doua grafuri sunt izomorfe.
7. Fiind dat un graf G = (X, U), sa se determine un lant simplu de lungime maxima.
8. Fiind dat un graf G = (X, U), sa se faca un program care sa verifice daca graful este bipartit
complet.
9. Sa se faca un program de generare a tuturor ciclurilor unui graf. Observatie: puteti adapta
programul realizat pentru generarea tuturor ciclurilor elementare.
10. Fie G un graf neorientat, cu n vrfuri i m muchii, reprezentat prin matricea de adiacen. S
se realizeze programe, n C/C++, care:
a) afieaz gradele tuturor vrfurilor;
b) afieaz vrfurile de grad par;
c) afieaz vrfurile izolate;
d) afieaz vrfurile terminale;
e) verific dac graful are vrfuri izolate;
t) verific dac graful are vrfuri terminale;
g) verific dac graful are vrfuri interioare (nu sunt nici izolate nici terminale);
h) verific dac graful are toate vrfurile izolate;
i) verific dac graful are toate vrfurile interioare (nu sunt nici izolate nici terminale):
j) afieaz gradul unui vrf dat:
k) afieaz vecinii unui nod dat, vf;
l) verific dac un vrf dat este terminal, izolat sau interior;
m) afieaz gradul cel mai mare i toate vrfurile care au acest grad
n) afieaz frecventa vrfurilor:
izolate: n1
terminale: n2
interioare: n3
o) fiind dat irul g1, ...,gn, s se verifice dac poate reprezenta irul gradelor vrfurilor n
aceast ordine;
p) fiind dat irul g1 ...,gn, s se verifice dac poate reprezenta irul gradelor vrfurilor (nu
neaprat n aceast ordine).

13

Grafuri orientate

Probleme rezolvate

1) Sa se parcurga in adancime ( DF ) un graf orientat. Graful este dat prin matricea de adiacenta.

#include<fstream.h>
#include<iostream.h>
int v[20],a[20][20],n;
void citire()
{
int i,j;
fstream f("matrice.txt",ios::in);
f>>n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
f>>a[i][j];
}
void df(int nod)
{
int k;
cout<<nod<<" ";
v[nod]=1;
for(k=1;k<=n;k++)
if((a[nod][k]==1) && (v[k]==0)) df(k);
}
int main()
{
citire();
df(1);
}

2) Matricea drumurilor - algoritmul Roy-Warshall


Se citeste un graf orientat cu n noduri si m arce, dat prin vectorul arcelor. Sa se construiasca o
matricea existentei drumurilor (a[i][j] este 1 daca exista drum de la i la j si 0 in caz contrar).
Ex: Pentru graful alaturat matricea existentei drumurilor este:
110010
110010
111111
111111
110010
111111

#include<fstream.h>
int k,m,n,x[100],a[100][100],p[100];
fstream f("graf.in",ios::in);
fstream g("graf.out",ios::out);
void citire()
{
int x,y;
f>>n>>m;
for(int i=1;i<=m;i++)
{
f>>x>>y;
a[x][y]=1;
}
}
void roy_warshall()
{
int i, j, k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
if(a[i][j]==0)
a[i][j]=a[i][k]*a[k][j];
}
void afisare()
{
for(int i=1;i<=n;i++)
{
g<<endl;
2

for(int j=1;j<=n;j++) g<<a[i][j]<<" ";


}
}
int main()
{
citire();
roy_warshall ();
afisare();
}
3) Se citesc 2 grafuri orientate, unul cu n noduri si m arce, iar celalalt cu k varfuri si l arce,
ambele date prin vectorul arcelor. Sa se determine daca al doilea graf este subgraf al primului.

#include<fstream.h>
fstream f("date1.in",ios::in);
fstream g("date2.in",ios::in);
int a[100][100],b[100][100],n,m,k,l;
void citire()
{
int x,y,i;
f>>n>>m;
for(i=1;i<=m;i++)
{
f>>x>>y;
a[x][y]=1;
}
g>>k>>l;
for(i=1;i<=l;i++)
{
g>>x>>y;
b[x][y]=1;
}
}
int subgraf()
{
for(int i=1;i<=k;i++)
for(int j=1;j<=k;j++)
if(a[i][j]!=b[i][j]) return 0;
return 1;
}
int main()
{

citire();
if(subgraf()) cout<<"este subgraf";
else cout<<"NU este subgraf";
}

4) Se da un graf orientat cu n varfuri si m arce prin lista arcelor. Stiind ca graful nu are varfuri
izolate, determinati daca este eulerian.
Exemple:
n=5 m=4
arcele:
12
23
34
45
nu este eulerian
n=5 m=10
arcele:
12
23
34
45
51
13
35
52
24
41
este eulerian
#include <fstream.h>
ifstream fin("date.in");
ofstream fout("date.out");
int a[50][50],n,m,ok;
int x[50], p[50], gfd_ext[50], grd_int[50];
void df(int nod)
{

int k;
p[nod]=1;
for(k=1;k<=n;k++)
if((a[nod][k]==1 || a[k][nod]==1) && !p[k]) df(k);
}
int main()
{
int v1,v2;
fin>>n>>m;
for(int i=1;i<=m;i++)
{
fin>>v1>>v2;
a[v1][v2]=1;
grd_ext[v1]++;
grd_int[v2]++;
}
df(1);
ok=1;
for(int i=1;i<=n;i++)
if(!p[i] || grd_ext[i]!=grd_int[i]) ok=0;
if(ok) fout<<"da";
else fout<<"nu";
fin.close();
fout.close();
}

5) Se da un graf orientat cu n varfuri si m arce prin lista arcelor. Se citeste apoi un numar k si o
submultime X cu k varfuri din multimea varfurilor grafului, notata cu V. Afisati arcele din graful
citit care au proprietatea ca au o extremitate in multimea X si cealalta in multimea V-X.
Exemplu:
6 7 (n,m)
12
21
34
15
45
56
61
3 (k)
1 2 3 (multimea x)
Arcele cerute sunt:
34
15
61

#include <fstream.h>
ifstream fin("date.in");
ofstream fout("date.out");
int n,m,k,v[100],a[100][100],p[100];
void citire()
{
int x,y;
fin>>n>>m;
for(int i=1;i<=m;i++)
{
fin>>x>>y;
a[x][y]=1;
}
fin>>k;
for(int i=1;i<=k;i++)
{
fin>>v[i];
p[v[i]]=1;
}
}
void afisare()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
{
if(a[i][j]==1&& p[i]!=p[j])fout<<i<<" "<<j<<endl;
}
}
int main()
{
citire();
afisare();
fin.close();
fout.close();
}

Probleme propuse spre rezolvare

1. S se ruleze programele prezentate mai sus, urmrind apelurile i valorile parametrilor de apel.
2. Celebritate.
Se d un grup format din n persoane, care se cunosc sau nu ntre ele. De la tastatur se introduc
m perechi de numere ntregi (x,y) cu semnificaia persoana x cunoate pe persoana y. relaia de
cunotin nu este neaprat reciproc. Numim celebritate, o persoan care este cunoscut de ctre
toate celelalte persoane din grup, dar ea nu cunoate pe nici un alt membru al grupului. S se
determine dac din grup exist o astfel de celebritate.

Grafuri orientate. Conexitate. Drumuri minime si maxime in grafuri


Probleme rezolvate
Aplicatie:
Enunt: Pentru alimentarea cu apa a unui cartier exista o statie de pompare a apei la care sunt
conectate cateva blocuri (nu toate). Stiind ca mai sunt conectate si unele blocuri intre ele
determinati daca pentru o configuratie data de conectare a blocurilor si a statiei de pompare
exista posibilitatea de alimentare cu apa a intregului cartier.
Datele de intrare au urmatoarea forma:
N-numarul de blocuri;
Ns-nodul de start;nr blocului unde este statia de pompare
xy
.
.
exista conexitate intre blocul x si blocul y;
.
.

Rezolvare:
Cu datele problemei se construieste un graf in care nodurile grafului reprezinta conexiunile
dintre blocuri. Se parcurge graful in latime avand drept nod de start blocul in care se afla statia
de pompare. Daca in urma parcurgerii s-au vizitat toate nodurile, inseamna ca se poate realiza
alimentarea cu apa a intregului cartier.
De exemplu, pentru configuratia urmatoare:
9
7
72
9
79
78
23
8
85
61
64
Se obtine graful:

7
Nod start
4
6
1

Si programul afiseaza:
Nu se poate alimenta cu apa intreg cartierul;
Pentru cel de-al doilea exemplu:
8
7
71
72
78
23
34
86
85

3
4
2
5

1
Se obtine graful:

7
Nod start

Si programul afiseaza:
Se poate alimenta cu apa intreg cartierul;
Codul sursa este urmatorul:
#include<iostream.h>
int c[100],v[100],a[20][20],nr,ns,n,m;
void citire()
{
int x,y,i,j;
cout<<"Dati numarul de noduri n = ";cin>>n;
cout<<"Dati nodul de start ns = ";cin>>ns;
cout<<"Dati numarul de muchii m = ";cin>>m;
for(i=1;i<=m;i++)
{
cout<<"dati x = ";cin>>x;
cout<<"dati y = ";cin>>y;
a[x][y]=1;
a[y][x]=1;
}
}
int prim_nevizitat()
{
int i=1;
while(v[i]!=0 && i<=n)
i++;
if(i<=n) return 1;
else
return n+1;
}
void parcurgere()
2

{
int i, lc, x;
nr=0;
while(ns<=n)
{
nr=nr+1;
c[1]=ns;
cout<<ns<<" ";
v[ns]=1;
lc=1;
while(lc!=1)
{
x=c[1];
for(i=1;i<=n;i++)
if(a[x][i]==1 && v[i]==0)
{
lc++;
c[lc]=i;
cout<<" "<<i;
v[i]=1;
}
for(i=1;i<=lc-1;i++)
c[i]=c[i+1];
lc=lc-1;
}
ns=prim_nevizitat();
}
}
int main()
{
citire();
parcurgere();
if(nr==1)
cout<<"Se poate alimenta cu apa intreg cartierul"<<endl;
else
cout<<"NU se poate alimenta cu apa intreg cartierul"<<endl;
}

Probleme propuse spre rezolvare

1. S se ruleze programul prezentat mai sus, urmrind apelurile i valorile parametrilor de apel.
2. Determinati vecinii unui varf al unui graf orientat.
3. Determinati gradele exterioare si interioare ale varfurilor unui graf, gradul exterior minim,
gradul exterior maxim, gradul interior minim si gradul interior maxim.
4. Verificati daca un graf este simetric/antisimetric.
5. Se citeste matricea de adiacenta a unui graf orientat. Sa se afiseze toate nodurile pentru care
d+(x)=d-(x) (gradul exterior este egal cu gradul interior). Pentru un nod x citit de la tastatura sa se
afiseze toate nodurile adiacente cu acestea.
6. Sa se verifice daca o secventa de noduri data reprezinta un drum elementar sau ne-elementar
intr-un graf orientat. Numarul de noduri, matricea de adiacenta, si secventa de noduri se citesc de
la tastatura.
7. Descrieti in pseudocod sau in C++ algoritmii de cautare in adancime si in latime in grafuri.
Parcurgeti in adancime, respectiv in latime urmatoarele grafuri:
a) Graf neorientat
1

b) Graf neorientat
2

3
4
8

1
7

6
4

c) Graf neconex
2

d) Graf orientat
2
1

4
5
e) Graf orientat
2
3
1

4
5
6
f) Graf neorientat conex
1

6
7

8
5