Professional Documents
Culture Documents
Grafet
Grafi eshte nje strukture matematikore qe perbehet nga nje bashkesi kulmesh dhe brinjesh
qe lidhin keto kulme. Formalisht brinjet trajtohen si cifte kulmesh, nje brinje (v, w) lidh kulmin
v me kulmin w. Formalisht:
V eshte bashkesia e kulmeve
E eshte nenbashkesi e V x V
Shkruajme G = (V, E) per te treguar qe G eshte nje graf me bashkesi kulmesh bashkesine V dhe
bashkesi brinjesh bashkesine E. Grafi G = (V, E) eshte i paorientuar atehere dhe vetem atehere
kur kur nqs per te gjitha kulmet v, w V, (v, w) E kemi (w, v) E. Nga perkufizimi duket qe
grafet e paorientuara jane raste te vecanta te grafeve te orientuar.
Bashkesia V dhe rrjedhimisht edhe bashkesia E jane te pafundme. Grafe te tilla gjejne
perdorim ne shume fusha, megjithate do te trajtojme vetem bashkesi te fundme V. Mqs E
eshte nenbashkesi e VxV atehere edhe E eshte e fundme.
Figura me poshte paraqet nje graf te orientuar me kulme dhe brinje te percaktuara nga
bashkesite:
V = {0, 1, 2, 3, 4, 5, 6} dhe
E = {(0, 2), (0, 4), (0, 5), (1, 0), (2, 1), (2, 5), (3, 1), (3, 6), (4, 0), (4, 5), (6, 3), (6, 5)}
Le te jete G=(V, E) nje graf me n kulme. Do ti emertojme kulmet e grafit me numra nga 0, 1,
..., n-1 ne nje menyre te zakonshme.
B.Bimbari -1-
Algoritmik Grafet
Matrica e fqinjesise per grafin G eshte nje matrice nxn A = (aij)0i, jn-1, ku aij = 1 nqs ka nje brinje
nga kulmi i tek kulmi j dhe 0 perndryshe.
Psh, matrica e fqinjesise per grafin e paraqitur ne Fig.1 eshte :
Matrica e fqinjesise varet nga menyra e emertimit te kulmeve te grafit. Matrica e fqinjesise qe
paraqet grafin eshte nje tabele dy dimensionale booleane, ku vlera TRUE (ose 1) tregon qe
ndermjet kulmit paraqitur nga rreshti perkates dhe kulmit paraqitur nga shtylla perkatese ka
nje brinje qe i lidh (pra jane fqinje). Vlera FALSE (ose 0) tregon qe ndermjet kulmeve nuk ka
nje brinje qe i lidh (pra nuk jane fqinje). Mund te ndodhe qe ne vend te vlerave 1 dhe 0 te kete
numra (rastet e grafeve me peshe). Perparesia kryesore e paraqitjes se grafeve me matrice
fqinjesie eshte se per te gjithe kulmet v dhe w mund te kontrollohet ne kohe konstante nese
ato jane fqinje ose jo (pra nese ka nje brinje qe i lidh apo jo).
Cmimi qe paguhet per aksesin e shpejte te shpjeguar me larte eshte kujtesa. Le te jete m numri
i brinjeve te grafit (m mund te jete te shumten n2).Nqs m eshte shume afer vleres n2 atehere
grafi quhet i dendur, ndersa nqs ajo eshte shume me e vogel sesa n2 grafi quhet i rralle. Ruajtja
e grafit do te kerkonte te pakten n+m vende ne kujtese, nderkohe perdorimi i matricave te
fqinjesise perdor n2 vende. Kjo vlere eshte shume me e madhe sesa n+m sidomos per grafet e
rralle (nje pjese e madhe e elementeve te matrices ka vlere 0). Algoritmet qe punojne me
grafet, duhet te inspektojne te gjitha brinjet e grafit te pakten njehere dhe, ne paraqitjen e
grafit me matrice fqinjesie keto algoritme trajtonin cdo element te matrices te pakten njehere
(per tu siguruar qe jane kontrolluar te gjitha brinjet). Algoritmet do te kerkonin O(n2) kohe
per tu ekzektuar.
Kur grafi paraqitet nepermjet listes se fqinjesise, perdoret nje tabele me n elemente, ku n
eshte numri i kulmeve te grafit. Cdo element i vektorit (qe i korrespondon nje kulmi v) eshte
nje liste e lidhur e cila permban te gjithe kulmet w qe lidhen me kulmin v nepermjet nje brinje.
Elementet e listes do te jene emertimet(numra, emra, etj, ne varesi te menyres se zgjedhur
per emertimin e kulmeve) e kulmeve fqinje. Nuk ka rendesi renditja e kulmeve w ne listen e
lidhur, pra nuk ka rendesi renditja e brinjeve qe ato paraqesin. Kjo gje duhet te kihet parasysh
edhe ne algoritmet qe punojne me grafet e paraqitura me keto struktura.
Grafi i paraqitur ne figuren 1 paraqitet nepermjet listave te fqinjesise si me poshte:
B.Bimbari -2-
Algoritmik Grafet
Per grafe te rralle paraqitja me liste fqinjesie eshte me eficente sesa paraqitja me matrica,
persa i perket hapesires. Per nje graf me n kulme dhe m brinje hapesira qe kerkohet eshte
(m+n), qe mund te jete shume me pak sesa (n2) hapesira e kerkuar kur grafi paraqitet me
matrice fqinjesie. Nga ana tjeter, per te gjetur nese ka nje brinje ndermjet dy kulmeve v dhe
w duhet te bridhet e gjithe lista e fqinjesise, e cila mund te kete te shumten n
elemente. Prandaj, testimi i kushtit te fqinjesise kerkon (n) hapa per paraqitjen me lista
fqinjesie, perkundrejt (1) hapave ne rastin e matrices se fqinjesise.
struct brinje{
int w; /* variabel per te ruajtur kulmin fundor te brinjes */
int pesha; /* peshe e brinjes, nese ka */
brinje * pas; /* shenjues tek elementi tjeter i linjes, qe paraqet
brinjen pasardhese ne liste */
};
struct graf{
brinje * brinjet[MAXK]; /* tabela me listen e fqinjesise, MAXK konstante
qe tregon numrin maximal te kulmeve */
int nKulmesh; /* numri kulmeve te grafit */
int nBrinje; /* numri brinjeve te grafit */
bool orientuar; /* indikator, graf i orientuar? */
};
Ne strukturat me lart, nje brinje (v,w) e orientuar paraqitet nepermjet nje brinje w ne listen e
fqinjesise se v. Nje brinje e paorientuar do te shfaqej dy here ne nje graf me kete strukture,
sepse do te ishte njehere ne listen e fqinjesise se v dhe njehere ne listen e fqinjesise se w.
return g;
}
Shtimi i nje brinje ne graf mund te realizohet nepermjet algoritmit shto_brinje me
poshte :
B.Bimbari -3-
Algoritmik Grafet
return g;
}
Pjesa me e madhe e algoritmeve te bredhjes se grafeve trajtojne cdo kulm dhe brinje sipas nje
rregulli te caktuar. Ne kete menyre algoritmet japin nje bredhje te grafit, dmth nje strategji
per te vizituar kulmet dhe brinjet sipas nje rregulli te pershtatshem.
Dy nga menyrat me te perhapura per bredhjen e grafit jane bredhja ne gjeresi (breadth-first
search) dhe bredhja ne thellesi (depth-first search). Te dyja fillojne nga nje kulm v dhe vizitojne
te gjithe kulmet e arritshme nga v (pra te gjithe fqinjet e tij). Nqs ka kulme qe mbeten te
pavizituara, dmth ka kulme qe nuk jane te arritshme nga v, atehere e vetmja menyre qe ato
te mund te listohen eshte qe kerkimi te zgjedhe nje kulm te ri te pavizituar v dhe te vizitoje
te gjitha kulmet e arritshme prej tij. Ky proces duhet te perseritet deri sa te jene vizituar te
gjitha kulmet.
B.Bimbari -4-
Algoritmik Grafet
fqinjet e 5, 4 dhe 1 jane vizituar, keshtu qe lista permban te gjithe kulmet e arritshem nga 0.
Ka edhe menyra te tjera sesi mund te zgjidhen kulmet qe trajtohen duke u nisur nga kulmi 0.
Nqs kulmet fqinje qe do te vizitohen zgjidhen ne rend numerik, atehere bredhja ne gjeresi
duke filluar nga 0 do te jepte 0, 2, 4, 5, 1. Kulmet 3 dhe 6 nuk jane te arritshme nga kulmi 0,
prandaj per ti vizituar ata duhet te fillohet nje bredhje tjeter ne gjeresi, psh nga kulmi 3.
Bredhja dhe sekuenca qe ajo prodhon varet shume nga kulmi ne te cilin fillohet. Psh
nqs bredhjen e fillojme ne kulmin 6, atehere te gjitha kulmet jane te arritshme dhe trajtohen
ne nje hap te gjitha. Sekuenca qe do merret eshte 6, 5, 3, 1, 0, 2, 4. Renditje tjeter qe mund te
gjenerohet eshte 6, 3, 5, 1, 0, 2, 4 dhe 6, 5, 3, 1, 0, 4, 2 ose 6, 3, 5, 1, 0, 4, 2.
Ne grafet e pa orientuara, numri i rezultateve te ndryshme te bredhjes ne gjeresi eshte
i pavarur nga zgjedhja e kulmit te fillimit.
Gjate bredhjes ne gjeresi te grafit, duhet te ruajme kulmet qe jane vizituar deri ne ate
moment dhe kulmet qe jane trajtuar plotesisht deri ne ate moment (dmth kulmet per te cilet
jane vizituar te gjithe fqinjet e tyre). Tabela booleane vizituar ka aq elemente sa eshte numri
i kulmeve te grafit. Cdo element ka vleren TRUE nqs kulmi te cilit ai i korrespondon eshte
vizituar. Kulmet qe jane vizituar, por qe nuk jane trajtuar plotesisht ruhen ne nje rradhe
Rradhe. Kjo garanton qe kulmet te trajtohen ne rendin e duhur kulmet qe vizitohen me pare
do te trajtohen me pare. Implementimi i algoritmit te bredhjes ne gjeresi jepet me poshte si
pseudokod.
Algoritem bredhje_ne_gjeresi(G)
1. Inicializo tabelen booleane vizituar me te gjitha vlerat FALSE
2. Inicializo Rradhen Q
3. per te gjitha v V bej
4. nqs vizituar[v] = FALSE atehere
5. bredhje_ne_gjeresi_nga_kulmi(G, v)
Algoritmi kryesor bredhje_ne_gjeresi inicializon tabelen vizituar dhe rradhen dhe me pas
bredh te gjitha kulmet. Per secilin kulm qe nuk eshte shenjuar si i vizituar, ai inicion nje
bredhje_ne_gjeresi_nga_kulmi. Algoritmi bredhje_ne_gjeresi_nga_kulmi viziton te gjitha
kulmet e arritshme nga kulmi fillestar sic u pershkrua me lart. Cikli ne rreshtat 5-8 mund te
implementohet duke perdorur bredhur listen e fqinjesise te kulmit v.
Ne implementimin e algoritmit te mesiperm te bredhjes ne gjeresi perdoren dy tabela
booleane per te ruajtur informacion per cdo kulm te grafit. Kulmi quhet i vizituar heren kur ai
vizitohet per here te pare nga algoritmi. Kulmi konsiderohet i procesuar (trajtuar plotesisht)
nqs eshte kaluar neper te gjitha brinjet qe dalin prej tij. Pra, gjate kerkimit, cdo kulm kalon nga
gjendja i pavizituar ne i vizituar dhe ne fund i procesuar.
B.Bimbari -5-
Algoritmik Grafet
struct Rradhe{
int vl;
Rradhe * pas;
};
if(r == NULL)
r = element;
else
{
tmp = r;
while(tmp->pas != NULL)
tmp = tmp->pas;
tmp->pas = element;
}
return r;
}
void inicializo_bredhje(graf *g)
{
for (int i=0; i<g->nKulmesh; i++)
{
procesuar[i] = vizituar[i] = false;
prindi[i] = -1;
}
}
q = shto_ne_rradhe(q,kulmFillimi);
vizituar[kulmFillimi] = true;
while (q != NULL)
{
Rradhe * fillim = q;
v = fillim->vl;
p = g->brinjet[v];
while (p != NULL)
{
y = p->w;
if (vizituar[y] == false)
B.Bimbari -6-
Algoritmik Grafet
{
q = shto_ne_rradhe(q,y);
vizituar[y] = true;
prindi[y] = v;
}
p = p->pas;
}
procesuar[v] = true;
fillim = fillim->pas;
q = fillim;
}
}
Bredhja ne gjeresi prodhon pemen(t) e bredhjes ne gjeresi. Kjo peme ka si rrenje kulmin s prej
nga nis bredhja ne thellesi dhe permban te gjitha kulmet e arritshme prej tij. Fillimisht
algoritmi shton ne kete peme vetem kulmin prej nga nis bredhja (s). Sa here qe algoritmi gjen
kulme te pazbuluar (psh ndonje kulm v, te arritshem nga ndonje kulm u ne listen e fqinjesise
se kulmit fillester), ai shton ne peme kulmin v dhe brinjen (u,v).
Bredhja ne thellesi qe fillon nga nje kulm v, viziton ne fillim v, pastaj ndonje fqinj w te v, pastaj
ndonje fqinje x te w qe nuk eshte vizituar me pare, e keshtu me rradhe. Kur algoritmi ngec
dmth i ka trajtuar te gjithe kulmet fqinje si me siper, kthehet dhe gjen kulmin e pare te vizituar
qe ka nje fqinje te vizituar. Ai vazhdon me bredhjen deri sa ti duhet te kthehet perseri
mbrapa. Ne kete menyre, algoritmi do te mbuloje te gjitha kulmet e arritshme nga v. Me pas
fillon nje bredhje tjeter ne thellesi. Kjo bredhje fillon nga ndonje kulm qe nuk eshte i arritshem
nga v dhe perseritet derisa te gjitha kulmet te jene vizituar.
Per grafin me poshte, nje bredhje ne thellesi qe fillon nga kulmi 0 do te jepte sekuencen
0, 2, 1, 5, 4. Pasi jane vizituar kulmet 0, 2 dhe 1, algoritmi kthehet tek kulmi 0 dhe viziton 4.
Bredhja ne thellesi qe fillon tek 0 mund ti vizitoje kulmet edhe ne rendin 0, 4, 5, 2, 1 ose 0, 5,
4, 2, 1 ose 0, 2, 5, 1, 4. Ashtu si dhe tek bredhja ne gjeresi, sekuenca e kulmeve qe jep algoritmi
varet nga radha ne te cilen trajtohen kulmet.
Bredhja ne thellesi mund te implementohet ne menyre te ngjashme me bredhjen ne
thellesi, duke perdorur nje stive ne vend te rradhes. Duke perdorur stive per te ruajtur kulmet
qe jane vizituar, por nuk jane procesuar, sigurohemi qe eksplorojme kulmet duke ecur perpara
ne shteg. Pra vizitojme nje fqinj te ri, nese ekziston nje fqinj dhe kthehemi kur i kemi vizituar
te gjithe fqinjet.
Algoritmi me poshte eshte nje implementim rekursiv i bredhjes ne thellesi. Prania e
rekursivitetit eleminon nevojen e perdorimit ne menyre eksplicite te stives.
Algoritem bredhje_ne_thellesi(graph G, u)
gjendje[u] = vizituar
for each v fqinjet[u] do
proceso_brinjen (u, v) //sipas nevojes
if gjendje[v] = pazbuluar then
paraardhesi [v] = u
B.Bimbari -7-
Algoritmik Grafet
bredhje_ne_thellesi(G, v)
gjendje[u] = procesuar
procesuar[v] = true;
}
4. Aplikime te bredhjeve te grafeve
4.1 Perdorime te bredhjes ne gjeresi
Pjesa me e madhe e algoritmeve ne grafe bredhin nje ose dy here grafin. Kur keto algoritme
perdorin listat e fqinjesise koha e ekzekutimit te tyre eshte lineare, mqs algoritmi i bredhjes
ne gjeresi ka kompleksitet O(m+n) (m- numri i brinjeve, n- numri i kulmeve).
Tabela prindi ne algoritmin e bredhjes ne gjeresi sherben per te gjetur shtigje ne graf. Kulmi
qe sherbeu si nisje kur u zbulua kulmi i percaktohet si prind[i]. Te gjitha kulmet zbulohen
gjate bredhjeve te grafit, keshtu qe te gjithe kulmet pervec rrenjes kane nje prind. Relacioni
prind percakton nje peme te bredhjes se grafit ku rrenja eshte kulmi fillestar ku fillon bredhja.
Gjate procesit te zbulimeve te kulmeve duke u nisur nga rrenja, distanca e tyre nga
rrenja rritet. Shtegu unik nga rrenja tek cdo kulm x permban numrin me te vogel te mundshem
te brinjeve qe lidhin brinjen me cdo kulm. Kjo eshte nje veti shume e rendesishme e pemes
qe krijohet sipas menyres se pershkruar me lart.
Shtegu mund te ndertohet duke ndjekur zinxhir paraardhesit e x per te arritur deri tek
rrenja. Duhet punuar duke ecur mbrapsht ne shteg sepse ai nuk mund te gjendet duke u nisur
nga rrenja. Prandaj mqs shtegu gjenerohet ne rend te kundert, duhet qe ose nepermjet
rekursivitetit ose nepermjet stivave te shnderrohet ne rendin korrekt.
B.Bimbari -8-
Algoritmik Grafet
Per grafin me poshte (dhe pemen perkatese te formuar per bredhjen ne gjeresi) algoritmi i
bredhjes ne gjeresi jep lidhjen kulm-prind sic eshte paraqitur ne tabele.
Kulmi 1 2 3 4 5 6
Prindi -1 1 2 5 1 1
Fig.5. Grafi G, pema e bredhjes se tij ne gjeresi dhe tabela e relacionit kulm-prind.
Algoritmi gjej_shteg per kulmet 1 dhe 4 gjen si shtegun me te shkurter mes ketyre dy
kulmeve shtegun {1, 5, 4}.
Kur perdoret algoritmi i bredhjes ne gjeresi per te gjetur shtegun me te shkurter ndermjet
kulmeve x dhe y duhet mbajtur parasysh qe:
- pema e shtegut me te shkurter hyn ne pune vetem kur bredhja ne gjeresi eshte
realizuar duke filluar nga kulmi x.
- algoritmi jep shtegun me te shkurter vetem nese grafi nuk eshte me peshe.
Nje graf eshte i lidhur nqs ekziston nje shteg ndermjet cdo dy kulmesh. Nje komponente e
lidhur ne nje graf te paorientuar eshte bashkesia maksimale e kulmeve e tille qe ndermjet cdo
dy kulmeve ekziston nje shteg. Studimi i komponenteve te lidhura eshte me rendesi sepse nje
numer i madh problemesh reduktohen ne gjetjen e komponenteve te lidhura te grafit.
Komponentet e lidhura mund te gjenden duke perdorur bredhjen ne gjeresi, mqs nuk
ka rendesi renditja e kulmeve. Fillohet nga kulmi i pare. Cdo kulm qe zbulohet gjate ketij
kerkimi duhet te jete pjese e te njejtit komponent te lidhur. Per te zbuluar komponente te
tjera, kerkimi perseritet duke nisur nga ndonje kulm i pazbuluar (nese ekziston nje kulm i tille).
Kjo perseritet derisa te gjenden te gjitha komponentet. Algoritmi paraqitet me poshte:
komponente_te_lidhura(graf *g)
{
int c; /* numri i komponenteve */
int i;
inicializo_kerkimin(g);
c = 0;
for (i=1; i<=g->nKulmesh; i++)
if (vizituar[i] == FALSE) {
B.Bimbari -9-
Algoritmik Grafet
c = c+1;
printf("Komponenti %d:",c);
bredhje_ne_gjeresi(g,i);
printf("\n");
}
}
Numri c inkrementohet sa here qe nis nje bredhje ne gjeresi nga nje kulm i pavizituar me pare.
Fakti qe gjenden kulme te pavizituar me pare do te thote qe nuk ka pasur nje shteg nga kulmi
i nisjes deri tek ky kulm, pra ai ndodhet ne nje komponente tjeter.
B.Bimbari - 10 -
Algoritmik Grafet
gjej_cikel(int x, int y)
{
if (prindi[x] == y) { /* u gjet brinje e kthimit pas! */
printf("Cikel nga %d to %d:",y,x);
gjej_shteg(y,x,prindi);
printf("\n\n");
}
}
B.Bimbari - 11 -
Algoritmik Grafet
struct brinje{
int w; /* variabel per te ruajtur kulmin fundor te brinjes */
int pesha; /* peshe e brinjes, nese ka */
brinje * pas; /* shenjues tek elementi tjeter i linjes, qe paraqet
brinjen pasardhese ne liste */
};
struct graf{
brinje * brinjet[MAXK]; /* tabela me listen e fqinjesise, MAXK
konstante qe tregon numrin maximal te kulmeve */
int nKulmesh; /* numri kulmeve te grafit */
int nBrinje; /* numri brinjeve te grafit */
bool orientuar; /* indikator, graf i orientuar? */
};
struct Rradhe{
int vl;
Rradhe * pas;
};
if(r == NULL)
r = element;
else
{
tmp = r;
while(tmp->pas != NULL)
tmp = tmp->pas;
tmp->pas = element;
}
return r;
}
B.Bimbari - 12 -
Algoritmik Grafet
{
g -> nKulmesh = 0;
g -> nBrinje = 0;
g -> orientuar = eshteIOrientuar;
for (int i=0; i<=MAXK; i++)
g-> brinjet[i] = NULL;
return g;
}
return g;
}
B.Bimbari - 13 -
Algoritmik Grafet
q = shto_ne_rradhe(q,kulmFillimi);
vizituar[kulmFillimi] = true;
while (q != NULL)
{
Rradhe * fillim = q;
v = fillim->vl;
p = g->brinjet[v];
while (p != NULL)
{
y = p->w;
if (vizituar[y] == false)
{
q = shto_ne_rradhe(q,y);
vizituar[y] = true;
prindi[y] = v;
}
p = p->pas;
}
procesuar[v] = true;
fillim = fillim->pas;
q = fillim;
}
}
B.Bimbari - 14 -
Algoritmik Grafet
procesuar[v] = true;
int main()
{
graf g;
graf * pg;
pg = &g;
pg->nKulmesh = nKulme;
pg->nBrinje = nBrinje;
afisho_graf(pg);
inicializo_bredhje(pg);
for (int i = 0; i < pg->nKulmesh; i++)
{
if(vizituar[i] == false)
bredhje_ne_gjeresi(pg, i);
}
B.Bimbari - 15 -
Algoritmik Grafet
cin>>kFund;
gjej_shteg(kFillim, kFund, prindi);
inicializo_bredhje(pg);
for(int i = 0; i < pg->nKulmesh; i++)
{
if(vizituar[i] == false)
bredhje_ne_thellesi(pg,i);
}
cout<<"\n"<<"Tabela prindi pas bredhjes ne thellesi
eshte:"<<"\n";
for(int i = 0; i < pg->nKulmesh; i++)
cout <<prindi[i]<<", ";
getch();
return 0;
}
B.Bimbari - 16 -