Sunteți pe pagina 1din 8

ATP - Sem 13

Arbori de cost minim

1. Algoritmul Kruskal
a) Etapele algoritmului
 Ordonare muchii dupa cost
 Se pleaca de la n arbori disjuncti H1, H2, ...Hn (n – nr de varfuri)
 Unificarea a doi dintre arborii existenti alesi intr-un anumit mod
 Alegerea celor 2 arbori – dintre toate muchiile nealese inca, se selecteaza cea de cost minim
 prin adaugarea acestei muchii u, din arborii Hi si Hj se formeaza un nou arbore
 dupa pasul n-2 obtinem un singur arbore

b) Exemplu
c) Implementare

Indicatii (graful se da de la tastatura prin matricea de costuri: zero unde nu exista muchie si cost unde exista muchie)

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>

#define VAL 999


int i,j,k,a,b,u,v,n,mA=1; //mA - muchii arbore
int min,costmin=0,cost[9][9],parinte[9];
// union - find
int gaseste(int i)
{
while(parinte[i])
i=parinte[i];
return i;
}
int uni(int i,int j)
{
if(i!=j)
{
parinte[j]=i;
return 1;
}
return 0;
}
int main()
{
printf("Implementare algoritm Kruskal\n");
printf("Dati numarul de noduri:");
scanf("%d",&n);
printf("Introduceti matricea de costuri (se va pune valoarea zero unde nu exista muchie)\n");
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&cost[i][j]);
if(cost[i][j]==0)
cost[i][j]=VAL;
}

printf("\n");

printf("Matricea costurilor este:\n");


for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
printf("%d\t", cost[i][j]);
printf("\n");
}

printf("\n");

printf("Arborele de cost minim este:\n");


while(mA < n)
{
for(i=1,min=VAL;i<=n;i++)
{
for(j=1;j <= n;j++)
{
if(cost[i][j] < min)
{
min=cost[i][j];
a=u=i;
b=v=j;
}
}
}
u=gaseste(u);
v=gaseste(v);
if(uni(u,v))
{
// Afisare muchii
printf("%d edge (%d,%d) =%d\n",mA++,a,b,min);
costmin +=min;
}
cost[a][b]=cost[b][a]=999;
}
// Afisare cost minim arbore
printf("\n\tCost minim = %d\n",costmin);
getch();
return 0;
}

2. Algoritmul Prim

a) Etapele algoritmului
 𝐸_0 se iniţializează ca mulţime vidă
 Alege un vîrf inițial oarecare 𝑣_0∈𝑉, 𝐴={𝑣_0 }, 𝐵=𝑉−𝐴
 Repetă de 𝑛−1 ori
o Alege muchia 𝑒=(𝑢,𝑣) cu cea mai mică pondere a.î. 𝑢∈𝐴 și 𝑣∈𝐵
o 𝐸_0←𝐸_0∪{𝑒}
o 𝐴←𝐴∪{𝑣}
o 𝐵←𝐵−{𝑣}
b) Exemplu

c) Implementare

Indicatii:
a) se creeaza un fisier text cu datele de intrare
exemplu continut graf:

7
11
122
174
233
252
266
273
341
352
451
563
675
2

b) codul

#include <stdio.h>
#include <malloc.h>
#include <conio.h>

//preia datele unui graf in forma tabelara din fisierul nume si obtine
//matricea ponderilor, unde MAX este valoarea cu seminificatie de infinit
//ultima linie a fisierului contine varful initial din algoritmul Prim

void preia_graf(char *nume, float ***w, int *n, int *v0, float MAX)
{
FILE *f=fopen(nume,"rt");
fscanf(f,"%i",n);
int i,j,m;
float **mw=(float **)malloc(*n*sizeof(float*));
for(i=0;i<*n;i++)
mw[i]=(float *)malloc(*n*sizeof(float));
fscanf(f,"%i",&m);
for(i=0;i<*n;i++)
for(j=0;j<*n;j++)
mw[i][j]=MAX;
for(i=0;i<m;i++){
int u,v;
float p;
fscanf(f,"%i",&u);
fscanf(f,"%i",&v);
fscanf(f,"%f",&p);
mw[u-1][v-1]=mw[v-1][u-1]=p;
}
fscanf(f,"%i",v0);
fclose(f);
*w=mw;
}

//implementarea algoritmului lui Prim


float Prim(float **w,int n, int v0, int ***arb, float MAX)
{
float cost=0;
int *ind=(int *)malloc(n*sizeof(int));
int i;
for(i=0;i<n;i++)
ind[i]=0;
ind[v0-1]=1;
//ind este vectorul indicator: ind[i]=1, daca varful i+1 a fost trecut in A, altfel este 0
int **muchii=(int **)malloc((n-1)*sizeof(int *));
for(i=0;i<n-1;i++)
muchii[i]=(int *)malloc(2*sizeof(int));
for(i=0;i<n-1;i++){
int u,v,vf1,vf2;
float cmin=MAX;
for(u=1;u<=n;u++)
if(ind[u-1])
for(v=1;v<=n;v++)
if((!ind[v-1])&&(w[u-1][v-1]<=cmin)){
vf1=u;
vf2=v;
cmin=w[u-1][v-1];
}
cost+=cmin;
muchii[i][0]=vf1;
muchii[i][1]=vf2;
ind[vf2-1]=1;
}
*arb=muchii;
free(ind);
return cost;
}

int main()
{
float **w,cost,MAX;
MAX=1000000;
int n,v0, **muchii;
preia_graf("graf.txt", &w, &n, &v0, MAX);
cost=Prim(w,n,v0,&muchii,MAX);
printf("Arborele de cost minim cu v0=%i\n",v0);
int i;
for(i=0;i<n-1;i++)
printf("(%i,%i) ",muchii[i][0],muchii[i][1]);
printf("\nCostul:%8.2f",cost);
for(i=0;i<n;i++)
free(w[i]);
free(w);
for(i=0;i<n-1;i++)
free(muchii[i]);
free(muchii);
getch();
}
Tema

Grafuri
1. Scrieti un subprogram care verifica daca un graf neponderat reprezentat tabelar este complet (intre oricare doua
varfuri exista muchie).
2. Scrieti un subprogram care, folosind reprezentarea tabelara a unui graf ponderat, determina varfurile izolate si
varfurile care au proprietatea ca sunt extremitate a cel putin k muchii, unde k este o valoare data.
3. Scrieti un subprogram care determina nodurile izolate ale unui graf orientat reprezentat prin matricea de adiacenta.
4. Scrieti un subprogram care determina componentele conexe ale unui graf, reprezentat tabelar, folosind metodele de
parcurgere in latime generalizata, adancime generalizata, matricea existentei drumurilor.
5. Determinati gradul unui nod din cadrul unui graf.
6. Scrieți un subprogram care determină dacă o secvență de vârfuri constituie un ciclu într-un graf.
7. Scrieti programul C ce contine subprogramul care verifica daca un graf neponderat este arbore.
Rezolvare: o modalitate de a verifica este aceea a a testa conditia daca graful este conex si daca numarul de varfuri este
cu 1 mai mare decat numarul de muchii.
8. Algoritmul lui Prim.

Greedy
1.Interclasare optima a n vectori – se da un numar de vectori, fiecare fiind sortat crescator. Sa se scrie subprogramul
care interclaseaza vectorii astfel incat sa se efectueze cat mai putine miscari de elemente.
2. Problema sumei maxime – se da o multime de elemente reale A={a1, a2, ..., an}. Se cere sa se scrie functia care
determina o submultime inclusa in A, astfel incat suma elementelor submultimii S sa fie cea mai mare posibila.
3. Se da o permutare P=(p1, p2, ...,pn). Se cere sa se descompuna aceasta permutare intr-un produs de transpozitii*: a)
oarecare si b) de forma (1,i).
Obs: o transpozitie este o permutare obtinuta din permutarea identica prin interschimbarea elementelor de pe pozitiile i
si j.
6. Problema rucsacului – forma intreaga (obiectele nu pot fi fractionate) si forma continua (obiectele pot fi fractionate si
se va utiliza intreaga capacitate de transport).
4. Fiind dat un numar natural k>1. Sa se scrie programul care determina cel mai mic numar natural avand exact k divizori
naturali proprii (diferiti de 1 si de n).
5. Construire arbore partial de cost minim asociat unui graf (Kruskal si Prim)

Anexa – aspecte teoretice

Arbori
1. Arbore = un graf conex si fara cicluri*
*Daca un digraf este ciclic sau aciclic se poate verifica utilizand algoritmul Marimont (vezi exemplu si implementare in suportul
de curs).
2. Orice arbore H=(X,V) cu n>=2 varfuri contine cel putin doua varfuri terminale.
3. Orice arbore cu n varfuri are n-1 muchii.
4. Un graf G =(X,U) care nu contine cicluri se numeste aciclic.
5. Un graf G este arbore daca si numai daca G este conex si n = m+1, unde n este nr. de vf si m nr. de muchii.
6. Un arbore orientat este un arbore directionat cu radacina.
7. Reprezentari arbori:
 FIU-FRATE – si exemplu
8. Parcurgeri:
 A-preordine
 A-postordine
 pe niveluri - exemplu

Arbore partial de cost minim (APM)


1. Fie un graf G. Un graf partial H al sau care in plus este si arbore se numeste arbore partial 2. Pentru graful G conex, cu
functia de cost c, exista un graf partial H conex si de cost minim, care in plus, este arbore.
 Algoritmul Kruskal
 Algoritmul Prim

Greedy
- metoda Greedy se aplica problemelor de optimizare
- metoda construieste solutia optima pas cu pas, la fiecare pas fiind selectat in solutie elementul care pare “cel mai bun” la
momentul respectiv, in speranta ca aceasta alegere locala va conduce la optimul global.
- algoritmii Greedy sunt foarte eficienti insa nu conduc in mod necesar la o solutie optima.

Descriere algoritm:
o se primeste multimea A cu n elemente
o se initializeaza solutia B ca multime vida
o se repeta de p<=n ori
 alege un element candidat x din multimea A
 verifica daca B reunit cu {x} este solutie acceptabila
 daca da, adauga x la multimea B. B = B reunit cu {x}
o se trimite multimea B ca solutie