Sunteți pe pagina 1din 10

Ministerul Educaţiei al Republicii Moldova

Universitatea Tehnică a Moldovei

RAPORT
Lucrare de laborator nr.5
la Matematica Discretă

Tema: Algoritmii Ford și Bellman-Calaba de determinare a


drumului minim.

A elaborat: st.gr.TI-191 Guțan Iurii

A verificat: Gorban Maria

Chișinău, 2020

1.Scopul lucrării:
 Studierea algoritmilor de determinare a drumurilor minime într-un graf.
 Elaborarea programelor de determinare a drumului minim într-un graf ponderat.
2.Considerații teoretice:
Noțiunea de drum minim
Pentru un graf orientat G = (X,U) se va numi drum un şir de vârfuri D = (x0, x1,..., xr) cu
proprietatea că (x0, x1), (x1, x2),..., (xr-1, xr) aparţin lui U, deci sunt arce ale grafului şi extremitatea
finală a arcului precedent coincide cu extremitatea iniţială a arcului următor.
Vârfurile x0 şi xr se numesc extremităţile drumului D. Lungimea unui drum este dată de numărul
de arce pe care le conţine. Dacă vârfurile x0, x1,..., xr sunt distincte două câte două drumul D este
elementar.
Adeseori, fiecărui arc (muchii) i se pune în corespondenţă un număr real care se numeşte
ponderea (lungimea) arcului. Lungimea arcului (xi, xj) se va nota w(i,j), iar în cazul în care un arc
este lipsă ponderea lui va fi considerată foarte mare (pentru calculator cel mai mare număr
pozitiv posibil). În cazul grafurilor cu arce ponderate (grafuri ponderate) se va considera
lungime a unui drum suma ponderilor arcelor care formează acest drum. Drumul care uneşte
două vârfuri concrete şi are lungimea cea mai mică se va numi drum minim iar lungimea
drumului minim vom numi distanţă. Vom nota distanţa dintre x şi t prin d(x, t), evident,
d(x,x)=0.
Algoritmul lui Ford pentru determinarea drumului minim
Permite determinarea drumului minim care începe cu un vârf iniţial xi până la oricare vârf al
grafului G. Dacă prin Lij se va nota ponderea arcului (xi, xj) atunci algoritmul conţine următorii
paşi:
1. Fiecărui vârf xj al grafului G se va ataşa un număr foarte mare Hj(∞). Vârfului iniţial i se va
ataşa Ho = 0;
2. Se vor calcula diferenţele Hj - Hi pentru fiecare arc (xi, xj). Sunt posibile trei cazuri:
a) Hj - Hi < Lij,
b) Hj - Hi = Lij,
c) Hj - Hi > Lij.
Cazul "c" permite micşorarea distanţei dintre vârful iniţial şi xj din care cauză se va realiza
Hj = Hi + Lij.
Pasul 2 se va repeta atâta timp cât vor mai exista arce pentru care are loc inegalitatea “c”. La
terminare, etichetele Hi vor defini distanţa de la vârful iniţial până la vârful dat xi.
3. Acest pas presupune stabilirea secvenţei de vârfuri care va forma drumul minim. Se va pleca
de la vârful final xj spre cel iniţial. Predecesorul lui xj va fi considerat vârful xi pentru care va
avea loc Hj - Hi = Lij. Dacă vor exista câteva arce pentru care are loc această relaţie se va
alege la opţiune.
Algoritmul Bellman-Calaba
Permite determinarea drumului minim dintre oricare vârf al grafului până la un vârf, numit vârf
final.
Etapa iniţială presupune ataşarea grafului dat G a unei matrice ponderate de adiacenţă, care se va
forma în conformitate cu următoarele:
1. M(i,j) = Lij, dacă există arcul (xi, xj) de pondere Lij;
2. M(i,j) = ∞, unde ∞ este un număr foarte mare (de tip întreg maximal pentru calculatorul
dat), dacă arcul (xi, xj) este lipsă;
3. M(i,j) = 0, dacă i = j.
La etapa a doua se va elabora un vector V0 în felul următor:
1. V0(i) = Lin, dacă există arcul (xi, xn), unde xn este vârful final pentru care se caută drumul
minim, Lin este ponderea acestui arc;
2. V0(i) = ∞, dacă arcul (xi, xn) este lipsă;
3. V0(i) = 0, dacă i = j.
Algoritmul constă în calcularea iterativă a vectorului V în conformitate cu următorul procedeu:
1. Vk(i) = min{Vk-1; Lij+Vk-1(j)}, unde i = 1, 2,…, n - 1, j = 1, 2,..., n; i<>j;
2. Vk(n) = 0.
Când se va ajunge la Vk = Vk-1 - STOP.
Componenta cu numărul i a vectorului Vk cu valoarea diferită de zero ne va da valoarea minimă a
drumului care leagă vârful i cu vârful n.
Sarcina de bază:
1. Elaboraţi procedura introducerii unui graf ponderat;
2. Elaboraţi procedurile determinării drumului minim;
3. Realizaţi un program cu următoarele funcţii:
 introducerea grafului ponderat cu posibilităţi de analiză sintactică şi semantică şi de
corectare a informaţiei;
 determinarea drumului minim;
 extragerea informaţiei la display şi printer (valoarea drumului minim şi succesiunea
vârfurilor care formează acest drum).

Programul:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define MAX 30000
void F();
void BK();
void Menu();

void ListAd();
void ElebList();
void DrumFord(int);

//structuri
struct Lista_incidenta{
int v;
int w;
struct Lista_incidenta *next;
};
struct Graph{
int h;
int p;
struct Lista_incidenta *first;
struct Lista_incidenta *last;
}*G;
int N,V;

void Ford()
{ int i,f=1;
struct Lista_incidenta *c;

if(G==NULL) return;
for(i=0;i<N;i++)
{ G[i].p=-1;
G[i].h=MAX;
}
printf("\n\t");
printf("Dati varful initial: ");
scanf("%d",&V);

G[--V].h=0;
while(f)
{ f=0;
for(i=0;i<N;i++)
{ c=G[i].first;
while(c!=G[i].last)
{ if(G[c->v].h>G[i].h+c->w)
{ G[c->v].h=G[i].h+c->w;
G[c->v].p=i;
f=1;
}
c=c->next;
}
}
}
for(i=0;i<N;i++)
{ printf("\n\r Drum minim din %d in %d este",V+1,i+1);
if(G[i].h==MAX) {printf(" nu exista.");}
else
{ DrumFord(i);
printf(" : Lungimea %d.\n",G[i].h);

}
}
}

void Bel_Kal()
{ int *t,i,j,k,f=1;
struct Lista_incidenta *c;
int *P=(int *)malloc(N*sizeof(int ));
int *VK=(int *)malloc(N*sizeof(int ));
int **M=(int **)malloc(N*sizeof(int *));
int *VK_1=(int *)malloc(N*sizeof(int ));
for(i=0;i<N;i++) M[i]=(int *)malloc(N*sizeof(int));
for(i=0;i<N;i++)
for(j=0;j<N;j++) M[i][j]=(i==j)?0:MAX;
for(i=0;i<N;i++)
{ c=G[i].first;
while(c!=G[i].last)
{ M[i][c->v]=c->w;
c=c->next;
}
}
printf("\n\t");
printf("Dati virful final: ");
scanf("%d",&V);

V--;
for(i=0;i<N;i++)
{ VK_1[i]=M[i][V];
P[i]=-1;
}
while(f)
{ for(i=0;i<N;i++) VK[i]=MAX;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
if(i!=j && VK[i]>VK_1[j]+M[i][j])
{ VK[i]=VK_1[j]+M[i][j];
P[i]=j;
}
VK[V]=0;
for(i=0;i<N && VK[i]==VK_1[i];i++);
f=(i==N)?0:1;
t=VK_1; VK_1=VK; VK=t;
}
for(i=0;i<N;i++)
{ printf("\n Drumul minim din %d in %d este",i+1,V+1);
if(VK_1[i]==MAX) { printf(" nu exista.");}
else
{ for(k=i,j=0;j<N && P[k]!=-1 && k!=V;j++)
{ if(!j) printf(": %d",k+1);
else printf("->%d",k+1);
k=P[k];
}
if(k==V || i<N-1) printf("->%d",V+1);
else printf(": %d",V+1);
printf(" : Lungimea: %d.\r",VK_1[i]);

}
}
for(i=0;i<N;i++) free(M[i]);
free(P); free(M); free(VK); free(VK_1);
}

//-------------------------------------------------------------------
/* Lista de adiacenta si matricea ponderilor*/
void ListAd()
{ int i,v,w;
struct Lista_incidenta *c;

if(G) ElebList();
printf("\n\t");
printf("Dati numarul de virfuri a grafului : ");
scanf("%d",&N);
G=(struct Graph *)malloc(N*sizeof(struct Graph));
printf("\n\t");
printf("Introduceti Lista de adiacenta: \n\n\r");
for(i=0;i<N;i++)
{ printf("%d|",i+1);

G[i].first=(struct Lista_incidenta*)malloc(sizeof(struct Lista_incidenta));


G[i].last=G[i].first;
G[i].last->next=NULL;
G[i].last->v=-1;
scanf("%d",&v);;
if(N<v || v<0)
{ system("cls");
printf("\n\n\n\n\n\t\t\t");

printf("Eroare!");

getch();

}
while(v)
{ G[i].last->v=v-1;
G[i].last->next=(struct Lista_incidenta*)malloc(sizeof(struct Lista_incidenta));
G[i].last=G[i].last->next;
G[i].last->next=NULL;
G[i].last->v=-1;
scanf("%d",&v);
if(N<v || v<0)
{ system("cls");
printf("\n\n\n\n\n\t\t\t");

printf("Eroare!");

getch();
}
}
}
system("cls");
printf("\n\t");
printf("Introduceti ponderea pentru fiecare arc:\n\n\r");
for(i=0;i<N;i++)
{ G[i].last=G[i].first;
while(G[i].last->v+1)
{ printf(" u%d%d| ",i+1,G[i].last->v+1);

scanf("%d",&w);
G[i].last->w=w;
G[i].last=G[i].last->next;
}
}

void ElebList()
{ struct Lista_incidenta *c,*t;
while(N--)
{ c=G[N].first;
while(c!=G[N].last)
{ t=c->next;
free(c);
c=t;
}
}
free(G);
}

void DrumFord(int v)
{ int k;
if(v!=V) {k=v; DrumFord(G[v].p);}
if(k!=v) printf(": %d",v+1);
else {printf("->%d",v+1); k++;}
}
int main()
{
int optiune;
do
{
system("CLS");
puts(" \t\t______________________________________________________");
puts(" \t\t-\t 1.Introducerea grafului -");
puts(" \t\t-\t 2.Algoritmul Ford: -");
puts(" \t\t-\t 3.Algoritmul Bellman-Kalaba: -");
puts(" \t\t-\t 0.Iesire -");
puts(" \t\t______________________________________________________");
printf("\n Alegeti optiunea: ");
scanf("%d",&optiune);
switch (optiune){
case 1:{
ListAd();
getch();
break;
}

case 2:{
Ford();
getch();
break;
}

case 3:{
Bel_Kal();
getch();
break;
}
}
}
while(optiune!=0);
}

Întrebările de autocontrol:
1. Ce se numeşte graf ponderat?
Există graful G, orice(xi, xj), numim Pij >0 – pondere, care se asociază cu lungimea
arcului. Lungimea drumului este suma ponderilor pe care îl formează. Graful pe care sunt
ponderi se numește ponderat .
2. Definiţi noţiunea de distanţă.
Drumul care uneşte două vârfuri concrete şi are lungimea cea mai mică se va numi
drum minim iar lungimea drumului minim vom numi distanţă.
3. Descrieţi etapele principale ale algoritmului Ford.
Algoritmul FORD conţine următorii paşi:
1. Fiecărui vârf xj al grafului G se va ataşa un număr foarte mare Hj(∞). Vârfului
iniţial i se va ataşa Ho = 0;
2. Se vor calcula diferenţele Hj - Hi pentru fiecare arc (xi, xj). Sunt posibile
trei cazuri:
a) Hj - Hi < Lij,
b) Hj - Hi = Lij,
c) Hj - Hi > Lij.
Cazul "c" permite micşorarea distanţei dintre vârful iniţial şi xj din care cauză se va
realiza Hj = Hi + Lij.
Pasul 2 se va repeta atâta timp cât vor mai exista arce pentru care are loc inegalitatea
“c”. La terminare, etichetele Hi vor defini distanţa de la vârful iniţial până la vârful dat xi.
3. Acest pas presupune stabilirea secvenţei de vârfuri care va forma drumul minim. Se
va pleca de la vârful final xj spre cel iniţial. Predecesorul lui xj va fi considerat vârful xi
pentru care va avea loc Hj - Hi = Lij. Dacă vor exista câteva arce pentru care are loc
această relaţie se va alege la opţiune.
4. Care sunt momentele principale în algoritmul Bellman-Calaba?
Algoritmul Bellman – Calaba permite determinarea drumului minim dintre oricare
vârf al grafului până la un vârf, numit vârf final.
Etapa iniţială presupune ataşarea grafului dat G a unei matrice ponderate de adiacenţă,
care se va forma în conformitate cu următoarele:
1. M(i,j) = Lij, dacă există arcul (xi, xj) de pondere Lij;
2. M(i,j) = ∞, unde ∞ este un număr foarte mare (de tip întreg maximal pentru
calculatorul dat), dacă arcul (xi, xj) este lipsă;
3. M(i,j) = 0, dacă i = j.
La etapa a doua se va elabora un vector V0 în felul următor:
1. V0(i) = Lin, dacă există arcul (xi, xn), unde xn este vârful final pentru care se caută
drumul minim, Lin este ponderea acestui arc;
2. V0(i) = ∞, dacă arcul (xi, xn) este lipsă;
3. V0(i) = 0, dacă i = j.
Algoritmul constă în calcularea iterativă a vectorului V în conformitate cu următorul
procedeu:
1. Vk(i) = min{Vk-1; Lij+Vk-1(j)}, unde i = 1, 2,…, n - 1, j = 1, 2,..., n; i<>j;
2. Vk(n) = 0.
Când se va ajunge la Vk = Vk-1 - STOP.
Componenta cu numărul i a vectorului Vk cu valoarea diferită de zero ne va da
valoarea minimă a drumului care leagă vârful i cu vârful
5. Prin ce se deosebeşte algoritmul Ford de algoritmul Bellman-Calaba?
Algoritmul FORD se deosebește de algotirmul Bellman-Calaba prin faptul că
algoritmul FORD permite determinarea drumului minim care începe cu un vârf iniţial xi
până la oricare vârf al grafului G, iar algoritmul Bellman – Calaba permite determinarea
drumului minim dintre oricare vârf al grafului până la un vârf, numit vârf final.
6. Cum se va stabili succesiunea vârfurilor care formează drumul minim?
Succesiunea vârfurilor care formează drumul minim se va stabili dupa calcularea
primei și a doua diferență Hj-Hi. Daca pondereai primei diferențe este egală cu a doua
diferența atunci vârful xi pleacă in xj .

Concluzie:Realizând lucrarea de laborator nr.5 am studiat algoritmul de determinare a


drumurilor minime într-un graf ,elaborând astfel programul cerut.Indicațiile metodice și
cunoștințele obținute în cadrul cursului mi-au facilitat însărcinarea și m-au ajutat să
realizez lucrarea în scurt timp.Cercetarea suplimentară a altor materiale pentru a da
răspuns la întrebările de autocontrol mi-a adăugat și alte cunoștințe noi ce-mi vor fi de
folos pe viitor. Algoritmul lui Ford și al lui Bellman-Calaba ne-a permis determinarea
drumului minim care începe cu un vârf inițial xi până la oricare vârf al grafului Gși
respectiv determinarea drumului minim dintre oricare vârf al grafului pănă la vârf,numit
vârf final.