Tipuri de grafuri

Grafuri hamiltoniene si grafuri euleriene

Definitie

Se numeste ciclu hamiltonian un ciclu elementar care contine toate varfurile grafului.

Definitie

Un graf se numeste hamiltonian daca are cel putin un ciclu hamiltonian.

TEOREMA

Fie G=(X,U) un graf. Daca gradul fiecarui varf este >=n/2 atunci graful este hamiltonian.

Observație: Conditia din teorema este necesara, dar nu si suficienta.

Aplicatie:

Ciclurile hamiltoniene sunt legate de problema comis-voiajorului care pleaca dintr-un oras si trebuie sa treaca o singura data prin celelalte orase si sa se intoarca de unde a plecat.

Problema:

Fiind dat un graf neorientat memorat prin matricea de adiacente sa se determine daca graful este Hamiltonian . In caz afirmativ sa se afiseze ul ciclu Hamiltonian altfel se va afisa un mesaj.

Pentru a rezolva problema vom utiliza tehnica backtracking. Vom incarca in stiva noduri distincte si adiacente, astfel incat pornind de la problema clasica de backtracking a permutarilor vom testa valoarea de pe nivelul k astfel:

·        Sa fie un nod adiacent cu precedentul adaugat. E necesar ca: a[st[k-1]][st[k]]=1, in caz contrar se returneaza 0

·        Nodul adaugat sa nu se regaseasca pe nivelurile anterioare . Trebuie ca st[k]¹st[i] unde iÎ{1,2…k-1}, in caz contrar se returneaza 0

·        Pentru a se incheia ciclul este necesar ca primul si ultimul nod sa fie adiacente. Adica:

a[st[1]][st[n]]=1, in caz contrar se returneaza 0

#include<fstream.h>

#include<conio.h>

#include<stdio.h>

int st[100],n,m,k,a[20][20];

int ns;

//k este este nivelul din stiva (indexul – vetorul solutie),curent

int e_valid()

{if(k>1)

if(!a[st[k-1]][st[k]])

return 0;

else

for(int i=1;i<=k-1;i++)//parcurg nivelurile anterioarenivelului curent

if(st[i]==st[k])

return 0;

if(k==n)

if(!a[st[1]][st[k]])

return 0;

return 1;

}

void afisare()

{for(int i=1;i<=n;i++)

cout<<st[i]<<” „;

cout<<st[1];

k=0; //determina iesirea la prima solutie

ns++;

}

void back()

{k=1; //pe primul nivel initial

while(k>0)//cand k va descreste la 0 algoritmul se incheie

if(st[k]<n)

{st[k]++;

if(e_valid())//daca elementul incarcat este valid

if(k==n)//verific daca am ajuns la solutia completa.

afisare();

else    //daca nu am solutia completa urc in stiva (maresc vectorul, adica pe k)

{k++;

st[k]=0;}

}

else

k–;

}

void main()

{clrscr();

fstream f;

f.open(„ham.in”,ios::in);

int u,v;

if(f)

cout<<„ok!”;

else

cout<<„eroare”;

cout<<endl;

f>>n>>m;

for(int i=1;i<=m;i++)

{f>>u>>v;

a[u][v]=a[v][u]=1;

}

cout<<„matricea de adiac „<<endl; // afisare matrice de adiacenta

for( i=1;i<=n;i++)

{for(int j=1;j<=n;j++)

cout<<a[i][j]<<” „;

cout<<endl;

}

back();

if(ns==0)

cout<<”nu exista solutii”;

getch();

}

Definitie

Un ciclu se numeste eulerian daca treceo singura data prin toate muchiile.

Definitie

Un graf se numeste eulerian daca are un ciclu eulerian.

TEOREMA

Un graf fara varfuri izolate se numeste eulerian daca si numai daca este conex si gradul fiecarui varf este par.

Observație

Dintre grafurile complete sunt euleriene cele cu numar impar de varfuri.

Definitie

O componenta conexa este un subgraf conexmaximal cu aceasta proprietate.

Definitie

O componenta conexa a unui graf G=(X,U) este un subgraf S=(Y,Z) cu proprietatea ca nu exista un lant care sa uneasca un varf din Y cu un varf din X-Y.

Observație

Fiecare varf izolat constituie o componenta conexa.

Codul sursa: Determinarea componentelor conexe

#include<iostream.h>

int a[20][20],cc[30];

int n,ncc,i,j,v; // ncc=nr. de componente conexe

void df(int v)

{

int i;

cc[v]=ncc;

for(i=1;i<=n;i++)

if( (a[v][i]==1) && (cc[i]==0) )

df(i);

}

int main(void)

{

cout<<„Dati numarul de varfuri n = „; cin>>n;

cout<<„Matricea 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];

}

ncc=0;

for(i=1;i<=n;i++) cc[i]=0;

for(i=1;i<=n;i++)

if (cc[i]==0)

{

ncc=ncc+1;

df(i);

}

for(i=1;i<=ncc;i++) // ncc = nr. de comp. conexe

{

cout<<„componenta „<<i<<” „;

for(j=1;j<=n;j++)

if(cc[j]==i)

cout<<j<<” „;

cout<<endl;

}

}

Considerăm ca exemplu graful de mai jos, cu n=8 vârfuri

2                         6

3

1                                                          7

5                               4         8

Soluţie

În funcţia principală main se citesc: numărul de vârfuri n , numărul de muchii m , precum şi cele m perechi de numere ce reprezintă extremităţile muchiilor grafului.

Elementele matricei de adiacenţă se vor tipări pe monitor. Tot în acest modul vom apela funcţia conex ().

În funcţia conex() verificăm dacă  graful este conex situaţie în care vom apela funcţia grad(), iar dacă graful nu este conex vom afişa un mesaj „graful nu este eulerian”.

Funcţia grad() verifică dacă gradele tuturor vârfurilor sunt numere pare.

Programul aferent este:

 

#include<stdio.h>

#include<conio.h>

int a[20][20],n,m,x,y,i,j;

void conex();

void grad();

void main()

{

clrscr();

printf(„Dati nr de muchii:”);

scanf(„%d”,&m);

printf(„Dati nr de varfuri:”);

scanf(„%d”,&n);

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

a[i][j]=0;

for(i=1;i<=m;i++)

{do{

printf(„\n Dati muchia nr %d: „,i);

scanf(„%d%d”,&x,&y);

} while(x==y||x<1||x>n||y<1||y>n);

a[x][y]=1;

a[y][x]=1;

}

printf(„\nMatricea de adiacenta corespunzatoare este:\n\n”);

for(i=1;i<=n;i++)

{for(j=1;j<=n;j++)

printf(„%2d”,a[i][j]);

printf(„\n”);

}

conex();

getch();

}

void conex()

{

int start,viz[20],c[20],pi,ps,z;

printf(„\nDati varful start:”);

scanf(„%d”,&start);

for(i=1;i<=n;i++)

{viz[i]=0;

c[i]=0;

}

ps=1;

pi=1;

c[pi]=start;

viz[start]=1;

while(ps<=pi)

{

z=c[ps];

for(i=1;i<=n;i++)

if(a[i][z]==1&&viz[i]==0)

{pi++;

c[pi]=i;

viz[i]=1;

}

ps++;

}

if(pi==n)

grad();

else

printf(„\nGraful nu este eulerian”);

}

void grad()

{

int grad,k;

k=0;

for(i=1;i<=n;i++)

{ grad=0;

for(j=1;j<=n;j++)

if(a[i][j])

grad++;

if(grad%2!=0)

k=1;

}

if(k==0)

printf(„\nGraful este eulerian”);

else printf(„\nGraful nu este eulerian”);

}

*Să se afişeze matricea de adiacentă a unui graf neorientat cu n noduri şi m muchii.

#include<iostream>
using namespace std;
int mat[10][10],n,m;
void citire()
{int a,b,i,m;
for(i=1;i<=m;i++)
{cout<<„Dati muchia”<<i<<„=”;
cin>>a>>b;
mat[a][b]=mat[b][a]=1;
}
}
void afisare()
{int i,j;
cout<<„Matricea de adiacenta”;
cout<<endl;
for(i=1;i<=n;i++)
{for(j=1;j<=n;j++)
cout<<mat[i][j]<<” „;
cout<<endl;
}
}
int main()
{int i,j;
cout<<„n=”;cin>>n;
cout<<„m=”;cin>>m;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
mat[i][j]=0;
citire();
afisare();
}

 

Grafuri neorientate. Probleme propuse

 

  • Fie un graf neorientat memorat prin matricea de adiacente si o succesiune de k noduri. Sa se determine daca succesiunea citita este un lant din graf
  • Din fisierele mat1.in si mat2.in se citesc doua matrici patratice associate grafurilor g1 si g2. Sa se deremine daca g2 este graf partial pentru g1
  • Fie o harta cu n orase. Cele n orase se citesc din fisier. Intre cele n orase exista m drumuri. Se cunosc distantele celor n drumuri.
    • Sa se determine daca orasul x si orasul y sunt vecine
    • Sa se afiseze lungimile tuturor localitatilor intre care exista drum direct
    • Sa se determine lungimea minima a drumului dintre doua localitati citite de la tastatura
  • La o receptie sunt invitate n personae. Se cunosc numele celor n persoane .  Intre anumite persoane exista relatii de colaborare. Sa se determine daca se pot dispune cele n personae la o masa rotunda astfel incat intre oricare doua personae alaturate sa existe relatii. Se citesc : numele persoanelor si cele m relatiile sub forma de perechi de nume
  • Un eschimos locuieste la iglul cu numarul z. El are o harta pe care sunt marcate iglu-urile din zona (numerotate de la 1 la n) si distantele dintre acestea. Stiind ca din cauza frigului eschimosul nu poate sa parcurga o distanta mai mare de 20 km fara oprire, afisati o varianta de a ajunge  la prietenul lui care locuieste la iglul cu numarul w, eventual cea mai scurta varianta care indeplineste cerinta data. Cati kilometri  a parcurs eschimosul?
  • Un graf neorientat este bipartit daca exista o partitie a multimii nodurilor in doua multimi A si B astfel incat oricare doua varfuri din aceeasi multime sa nu fie adiacente. Sa se scrie un program care verifica daca un graf este bipartit si in caz afirmativ sa se tipareasca multimile A si B
  • Problema colorarii unei harti. Se citesc 4 culori (siruri de caractere) si denumirile a n tari (siruri de caractere) . Sa se coloreze harta astfel incat sa nu existe doua tari alaturate avand aceeasi culoare.  Se va afisa o solutie : tara-culoare, tare-culoare etc.
  • Sa se coloreze un graf astfel incat oricare doua muchii incidente cu acelasi nod sa fie colorate diferit. Care este numarul minim de culori necesar.
  • O pestera are n incaperi, fiecare situata la o adancime h. Configuratia pesterii este data de cele m culoare de acces intre camerele pesterii (culoarele sunt date ca extremitati). In incaperea s exista un izvor de apa sulfuroasa. Se dau n, m, cele m culoare (ca perechi x-y), s si adancimile h ale camerelor. Determinati incaperile inundate si culoarele umezite.
  • Fie un graf neorientat. Sa se determine daca graful contine cicluri.