Sunteți pe pagina 1din 10

Universitatea Tehnica a Moldovei

Facultatea Calculatoore, Informatica si Microelectronica


Catedra Tehnologii Informaionale

Lucrare de laborator 3
la
Analiza si Proiectarea Algoritmilor

Efectuat de
St.gr.
Caisin Ion

FAF-091

Verificat de: prof.


Catruc Mariana

Chiinu 2010

LUCRARE DE LABORATOR NR. 3


Tema:Algoritmi greedy
Scopul lucrrii:
1. Studierea tehnicii greedy.
2. Analiza i implementarea algoritmilor greedy.

1. Algoritmul lui Kruskal


Arborele parial de cost minim poate fi construit muchie, cu muchie, dup urmtoarea metoda a lui Kruskal
(1956): se alege nti muchia de cost minim, iar apoi se adaug repetat muchia de cost minim nealeas anterior i care
nu formeaz cu precedentele un ciclu. Alegem astfel #V1 muchii. Este uor de dedus c obinem n final un arbore.
Este nsa acesta chiar arborele parial de cost minim cutat?

Proprietatea 1. n algoritmul lui Kruskal, la fiecare pas, graful parial <V, A> formeaz o pdure de
componente conexe, n care fiecare component conex este la rndul ei un arbore parial de cost minim pentru
vrfurile pe care le conecteaz. n final, se obine arborele parial de cost minim al grafului G.
Pentru a implementa algoritmul, trebuie s putem manipula submulimile formate din vrfurile componentelor
conexe. Folosim pentru aceasta o structura de mulimi disjuncte i procedurile de tip find i merge (Seciunea 3.5). n
acest caz, este preferabil s reprezentm graful c o lista de muchii cu costul asociat lor, astfel nct s putem ordona
aceast list n funcie de cost. Iat algoritmul:

function Kruskal(G = <V, M>)


{iniializare}
sorteaz M cresctor n funcie de cost
n #V
A {va conine muchiile arborelui parial de cost minim}
iniializeaz n mulimi disjuncte coninnd fiecare cate un element din V
{bucla greedy}
repeat
{u, v} muchia de cost minim care nc nu a fost considerat
ucomp find(u)
vcomp find(v)
if ucomp vcomp then merge(ucomp, vcomp)
A A {{u, v}}
until #A = n-1
return A

Pentru un graf cu n vrfuri i m muchii, presupunnd c se folosesc procedurile find3 i merge3, numrul de
operaii pentru cazul cel mai nefavorabil este n:

O(m

log m) pentru a sorta muchiile. Deoarece m n(n1)/2, rezulta O(m log m) O(m log n). Mai mult, graful fiind
conex, din n1 m rezulta i O(m log n) O(m log m), deci O(m log m) = O(m log n).
O(n)

pentru a iniializa cele n mulimi disjuncte.


Cele cel mult 2m operaii find3 i n1 operaii merge3 necesita un timp n O((2mn1) lg* n). Deoarece
O(lg* n) O(log n) i n1 m, acest timp este i n O(m log n).
O(m)

pentru restul operaiilor.

Deci, pentru cazul cel mai nefavorabil, algoritmul lui Kruskal necesit un timp n O(m log n).
O alt variant este s pstram muchiile ntr-un min-heap. Obinem astfel un nou algoritm, n care iniializarea
se face ntr-un timp n O(m), iar fiecare din cele n1 extrageri ale unei muchii minime se face ntr-un timp n
O(log m) = O(log n). Pentru cazul cel mai nefavorabil, ordinul timpului rmne acelai cu cel al vechiului algoritm.
Avantajul folosirii min-heap-ului apare atunci cnd arborele parial de cost minim este gsit destul de repede i un
numr considerabil de muchii rmn netestate. n astfel de situaii, algoritmul vechi pierde timp, sortnd n mod inutil
i aceste muchii.

Source code
Algoritmul Kruskal
#include<stdio.h>
#include<conio.h>
#include<process.h>
#include<iostream.h>
#include <time.h>
#include <dos.h>
struct Graf
{
int x;
int y;
int cost;
}*arc,*virf;
int nv,na,*set,*nod,*h,**mad;
void introd()
{
int i,j;
cout<<"\n|V| = ";
cin>>nv;nod=new int[nv];set=new int[nv];h=new int[nv];
for(i=0;i<nv;i++) { nod[i]=i; set[i]=i; h[i]=0;}
cout<<"\\n\t\t nGive < A > = "; cin>>na; arc=new Graf[na];
cout<<"\n\n\t Give x, y, and price :\n";
for(i=0;i<na;i++)
{ cin>>arc[i].x;arc[i].x-=1; cin>>arc[i].y;arc[i].y-=1; cin>>arc[i].cost; }
}
void merge(int a,int b)
{ if(a!=b) { if(h[a]==h[b]) {
h[a]++;set[b]=a;
}
else {if(h[a]>h[b]) set[b]=a;
else set[a]=b; }}}
int gaseste(int x)
{int i,j,r=x; while(set[r]!=r) r=set[r]; i=x;
while(i!=r) { j=set[i]; set[i]=r; i=j; }
return r;}
void SortCost(int &count)
{ int i,j; Graf tmp;
for(i=0;i<na-1;i++){
count++; for(j=i+1;j<na;j++) {

count++; if(arc[i].cost>arc[j].cost)
{tmp=arc[j]; arc[j]=arc[i]; arc[i]=tmp;}}}}
void Kruskal()
{
int count=0; SortCost(count); virf=new Graf[nv-1];
Graf tmp; int j=0,ucomp,vcomp;
for(int i=0;i<nv-1;i++)
{count++; do { count++;
tmp=arc[j]; ucomp=gaseste(arc[j].x);
vcomp=gaseste(arc[j].y); if(ucomp!=vcomp)
{ merge(ucomp,vcomp); virf[i]=tmp; break;}
j++; } while (1); }
cout<<"\n\n\t\t NUmber of iteration is : "<<count<<"\n\n";
}
void AfisVirf()
{
cout<<"\n\nVirfurile prelucrate sunt : {";
for(int i=0;i<nv;i++)
cout<<nod[i]+1<<",";
printf("%c}",8);
}
void AfisMuchii()
{
cout<<"\n\t Muchiile ce participa in algoritmul Kruskal sunt :\n";
for(int i=0;i<nv-1;i++)
cout<<"\n("<<virf[i].x+1<<","<<virf[i].y+1<<"); cu costul = "<<virf[i].cost;
}
void main()
{
clrscr();
cout<<"\n\t\tALGORITMUL KRUSKAL\n";
int L=0;
introd();
clock_t start,end;
start=clock();
Kruskal();
end=clock();
printf("Timpul de executie este : %.2f\n",(end-start)/CLK_TCK);
AfisMuchii();AfisVirf();
for(int i=0;i<nv-1;i++)
L=L+virf[i].cost;
cout<<"\n\nLmin = "<<L;
getch();
}

Algoritmul lui Prim


n algoritmul lui Prim, la fiecare pas, <U, A> formeaz un arbore parial de cost minim pentru
subgraful <U, A> al lui G. n final, se obine arborele parial de cost minim al grafului G.
Presupunem c vrfurile din V sunt numerotate de la 1 la n, V = {1, 2, ..., n}, matricea simetric C d
costul fiecrei muchii, cu C[i, j] = , dac muchia {i, j} nu exist. Folosim dou tablouri paralele. Pentru
fiecare i V \ U, vecin[i] conine vrful din U, care este conectat la i printr-o muchie de cost minim,
mincost[i] d acest cost. Pentru i U, punem mincost[i] = 1. Mulimea U, n mod arbitrar iniializat cu
{1}, nu este reprezentat explicit. Elementele vecin[1] i mincost[1] nu se folosesc.

function Prim(C[1 .. n, 1 .. n])


{iniializare, numai vrful 1 este n U}
A
for i 2 to n do vecin[i] 1
mincost[i] C[i, 1]
{bucla greedy}
repeat n1 times
min +
for j 2 to n do
if 0 < mincost[ j] < min then min mincost[ j]
kj
A A {{k, vecin[k]}}
mincost[k] 1 {adaug vrful k la U}
for j 2 to n do
if C[k, j] < mincost[ j] then mincost[ j] C[k, j]
vecin[ j] k
return A
Source Code (C/C++)
#include<stdlib.h>
#include<dos.h>
#include<time.h>
#include<stdio.h>
#include<conio.h>
#include<process.h>
#include<iostream.h>
struct Graf
{ int x,y,cost;
Graf(int x,int y,int c)
{ this->x=x; this->y=y; this->cost=c;}
Graf(Graf&a)
{ this->x=a.x; this->y=a.y; this->cost=a.cost;}}**arc,**virf;
int nv,na,*nod,*u,*vecin,*costmin,**matr;
void introd()
{int i,j,x,y,c; cout<<"\n|V| = "; cin>>nv;
nod=new int[nv]; for(i=0;i<nv;i++) nod[i]=i;
cout<<"\n|A| = "; cin>>na; arc=new Graf*[na];
cout<<"\nDati x, y, costul :\n";
for(i=0;i<na;i++) {cin>>x;x-=1; cin>>y;y-=1;
cin>>c; arc[i]=new Graf(x,y,c); } }
void Big()
{ int i,j; matr=new int*[nv];
for(i=0;i<nv;i++)
{ matr[i]=new int[nv]; for(j=0;j<nv;j++)
matr[i][j]=999;} for(i=0;i<na;i++)
{ matr[arc[i]->x][arc[i]->y]=arc[i]->cost;
matr[arc[i]->y][arc[i]->x]=arc[i]->cost;}}
Graf *find(int k,int j)
{
for(int i=0;i<na;i++)
if((arc[i]->x==k&&arc[i]->y==j)||(arc[i]->y==k&&arc[i]->x==j))
return arc[i];
return arc[0];
}

void Prim(int &count)


{
int i,j,k,min; vecin=new int[nv];
costmin=new int[nv]; u=new int[nv];
for(i=0;i<nv;i++) u[i]=-1;
virf=new Graf*[nv-1]; Graf *tmp;
u[0]=random(nv); for(i=0;i<nv;i++)
{count++; if(i==u[0]) continue;
vecin[i]=u[0]; costmin[i]=matr[i][u[0]];}
for(i=0;i<nv-1;i++)
{count++;min=999;
for(j=1;j<nv;j++)
{count++;
if(0<costmin[j]&&costmin[j]<min)
{min=costmin[j];k=j;}}
tmp=find(k,vecin[k]);
virf[i]=tmp;costmin[k]=-1;
for(j=1;j<nv;j++){count++;
if(matr[k][j]<costmin[j]){
costmin[j]=matr[k][j]; vecin[j]=k;}}}}
void AfisVirf()
{
cout<<"\n\nVirfurile prelucrate sunt : {";
for(int i=0;i<nv;i++)
cout<<nod[i]+1<<",";
printf("%c}",8);
}
void AfisMuchii()
{
cout<<"\n\nMuchiile ce participa in algoritmul Prim sunt :\n";
for(int i=0;i<nv-1;i++)
cout<<"\n("<<virf[i]->x+1<<","<<virf[i]->y+1<<"); cu costul = "<<virf[i]->cost;
}
void main()
{
clrscr();
cout<<"\n\t\tALGORITMUL PRIM\n";
int L=0,count=0;
introd();Big();
clock_t start,end;
start=clock();
Prim(count);
end=clock();
cout<<"\nNr. de iteratii este : "<<count;
printf("\n\nTimpul de executie este : %.2f",(end-start)/CLK_TCK);
AfisMuchii();AfisVirf();
for(int i=0;i<nv-1;i++)
L=L+virf[i]->cost;
cout<<"\n\nLmin = "<<L;
getch();
}

Algoritmul lui Dijkstra


Problema este de a determina lungimea celui mai scurt drum de la surs ctre fiecare vrf din graf.
Notm cu C mulimea vrfurilor disponibile (candidaii) i cu S mulimea vrfurilor deja selectate. n fiecare
moment, S conine acele vrfuri a cror distan minim de la surs este deja cunoscut, n timp ce mulimea
C conine toate celelalte vrfuri. La nceput, S conine doar vrful surs, iar n final S conine toate vrfurile
grafului. La fiecare pas, adugam n S acel vrf din C a crui distan de la surs este cea mai mic.
Algoritmul este:
function Dijkstra(L[1 .. n, 1 .. n])
{iniializare}
C {2, 3, ..., n}
{S = V \C exist doar implicit}
for i 2 to n do D[i] L[1, i]
{bucla greedy}
repeat n2 times
v vrful din C care minimizeaz D[v]
C C \ {v}
{si, implicit, S S {v}}
for fiecare w C do
D[w] min(D[w], D[v]+L[v, w])
return D
(Source Code C/C++)
#include<stdio.h>
#include<conio.h>

#include<process.h>
#include<iostream.h>
#include<time.h>
#include<dos.h>
struct El
{int val; int mark;}*d;
struct Graf
{int x,y,c; Graf(){x=0;y=0;}
Graf(int x,int y)
{this->x=x;this->y=y;}}*arc;
int nv,na,*s,**matr;
void introd()
{
int i,j,k; cout<<"\n|V| = "; cin>>nv;
cout<<"\n|A| = "; cin>>na; arc=new Graf[na];
cout<<"\nDati x, y, costul :\n";
for(i=0;i<na;i++){
cin>>arc[i].x;arc[i].x-=1;
cin>>arc[i].y;arc[i].y-=1;
cin>>arc[i].c;}}
void Big()
{int i,j; matr=new int*[nv];
for(i=0;i<nv;i++)
{matr[i]=new int[nv];
for(j=0;j<nv;j++)
matr[i][j]=999;
}
for(i=0;i<na;i++)
matr[arc[i].x][arc[i].y]=arc[i].c;
}
void init()
{int i;s=new int[nv];d=new El[nv];
for(i=0;i<nv;i++)
{d[i].val=matr[0][i];
d[i].mark=0;s[i]=-1;}d[0].mark=1;s[0]=0;}
void Dijkstra(int &count)
{int i,j,k,min,pmin,add;
init();for(i=1;i<nv;i++)
{min=999;for(j=1;j<nv;j++){count++;
if(d[i].val<min&&d[i].mark==0)
{min=d[i].val;
pmin=i;}}add=min;
s[i]=pmin;d[pmin].mark=1;
for(j=1;j<nv;j++){count++;
if((matr[i][j]+add)<d[j].val)
d[j].val=(matr[pmin][j]+add);}}cout<<"\n\nD = ["; for(i=1;i<nv;i++)
{ cout<<" "<<d[i].val;}cout<<" ]";}
void main()
{clrscr();cout<<"\n\t\tALGORITMUL DIJKSTRA\n";
int count=0; introd();Big();
clock_t start,end; start=clock(); Dijkstra(count);
end=clock(); cout<<"\n\nNr de iteratii este : "<<count;
printf("\n\nTimpul de executie este : %.2f",(end-start)/CLK_TCK);getch();}

end=clock();
cout<<"\n\nNr de iteratii este : "<<count;
printf("\n\nTimpul de executie este : %.2f",(end-start)/CLK_TCK);
getch();}

Concluzie :
Efectuind lucrarea de laborator am studiat algoritmii greedy si anume algoritmii :
Kruskal, Prim si Dijkstra. Algoritmii Kruskal si Prim ne dau posibilitatea sa construim arborele
de cost minim. Algoritmul Dijkstra ne da posibilitatea sa determinam drumurile minimale pina
la fiecare virf in parte. Implementind si analizind algoritmul Kruskal si Prim am ajuns la
concluzia ca acesti algoritmi sunt rapizi si rezulta ca sunt algoritmi eficienti si foarte buni
pentru rezolvarea problemei de construire a arborelui de cost minim. Algoritmul Dijkstra de
asemenea este un algoritm foarte eficient. Timpul de executie necesar pentru rezolvarea sarcinei
este minimal. Am folosit limbajul C++ pentru constriuirea codului sursa pentru program , am
intilnit greutati la structure de date , dar pina in sfirsit programul a fost facut efficient.

10