Documente Academic
Documente Profesional
Documente Cultură
e
=
U u
u c G c ) ( ) (
Funcia c se numete funcia cost.
Fie G=(X,U) un graf conex, reprezentat prin matricea costurilor. Se tie c prin eliminarea
uneia sau a mai multor muchii se obine un graf parial. Dac graful parial al unui graf G conex este
arbore, acesta se numete arbore parial al lui G. Dac dintr-un graf conex G=(X,U) se elimin
muchii astfel nct s se obin un arbore parial al crui cost s fie minim, acesta se numete arbore
parial de cost minim(APM).
Proprietate: Pentru graful G conex, cu funcia de cost c, exist un graf parial H conex i de cost minim,
care este i arbore.
Pentru determinarea APM sunt cunoscui mai muli algoritmi, cei mai utilizai fiind algoritmul lui
Kruskal (1956) i algoritmul lui Prim, ambii bazai pe o strategie Greedy.
Algoritmul lui Kruskal
Se pleac iniial de la n arbori disjunci, fiecare fiind format dintr-un nod al grafului : H
1
,
H
2
,.,H
n
. La fiecare pas vom ncerca s unificm doi dintre arborii existeni, alegerea celor doi arbori
ce vor fi unificai fcndu-se astfel: dintre toate muchiile nealese nc, se selecteaz muchia de cost
minim care are o extremitate ntr-un arbore i cealalt extremitate n alt arbore. Prin adugarea acestei
muchii la arborele care se construiete, se vor unifica cei doi arbori disjunci ntr-unul singur. Dup n-1
pai se obine APM care conine n-1 muchii.
Algoritmul pseudocod corespunzator este:
algoritm Kruskal(G,U)
AC
pentru fiecare varf ve X(G) executa
Formeaza_Multime(v)
sfarsit pentru
sorteaza muchiile din u in ordinea crescatoare a costului c
pentru fiecare muchie (u,v)eU(G),in ordinea crescatoare a costului
executa
daca Gaseste_Multime(u)=Gaseste_Multime(v) atunci
AA {(u,v)}
Uneste(u,v)
sfarsit daca
sfarsit pentru
returneaza A
Algoritmul folosete o structur de date pentru mulimi disjuncte pentru reprezentarea mai multor mulimi
de elemente disjuncte. Fiecare mulime conine vrfurile unui arbore din pdurea curent. Funcia
Gaseste_Multime(u) returneaz un element reprezentativ din mulimea care l conine pe u. Astfel,
putem determina dac dou vrfuri u i v aparin aceluiai arbore testnd dac Gaseste_Multime(u)
este egal cu Gaseste_Multime(v). Combinarea arborilor este realizat de funcia Uneste(u,v).
Pentru a implementa algoritmul lui Kruskal vom reprezenta graful prin vectorul muchiilor,
fiecare muchie avnd ataat i costul. Pentru a specifica la fiecare pas din ce arbore face parte un nod i,
vom folosi vectorul L. Iniial, pornim cu n arbori disjunci, deci L[i]=i , pentru ie{1,2,.n}. Pentru a
eficientiza alegerea muchiilor, vectorul muchiilor u se va ordona cresctor dup costul muchiilor.
Pentru a alege cele n-1 muchii ale APM se parcurg elementele vectorului u astfel:
Fie v=[u[i].x,u[i].y] muchia ce urmeaz a fi analizat (plecm cu i=1). Dac n vectorul L
extremitile muchiilor au valori egale, adic L[u[i].x]=L[u[i].y], atunci cele dou extremiti
aparin aceluiai subarbore, deci alegerea acestei muchii ar duce la formarea unui ciclu. n caz contrar,
nseamn c extremitile muchiei fac parte din subarbori diferii, fie aceatia H
x
i H
y
, care pot fi unificai,
operaie care presupune c pentru toate vrfurile celor doi arbori trebuie s apar n vectorul L aceeai
valoare (provenit din primul sau din al doilea arbore). Acest pas se repet pn am reuit s alegem
cele n-1 muchii ale APM.
Exemplu: Fie graful din figura urmtoare:
Pasii algoritmului sunt:
Configuratia initiala:
Dup ordonarea
cresctoare a muchiilor
dup costul c ataat,
avem:
u=([5,4],[3,4],[3,5],[1,2],
[2,5],[2,3],[6,5],[2,6],[2,7],
[1,7],[7,6])
c=(1,1,2,2,2,3,3,3,3,4,5)
L=(1,2,3,4,5,6,7) , fiecare nod fcnd parte dintr-un arbore.
Pasul 1:
Se alege muchia de cost minim [5,4]
i L devine: (1,2,3,5,5,6,7)
deoarece am unificat arborii H
4
i H
5
i
am obinut subarborele H
5
=(4,5).
Ceilali subarbori rmn nemodificai.
Pasul 2:
Se alege muchia [3,4]
de cost minim, unificm H
3
i H
5
i
obinem L=(1,2,3,3,3,6,7) i
H
3
=(3,4,5).
Pasul 3:
Se verific muchia [3,5] care nu poate fi
aleas deoarece L[3]=L[5] (vrfurile 3 i 5
aparin deja aceluiai subarbore H
3
) i alegerea ei
ar provoca apariia unui ciclu.
Se alege muchia [1,2], se unific H
1
i
H
2
i obinem: L=(1,1,3,3,3,6,7) i
H
1
=(1,2).
Pasul 4:
Se alege muchia [2,5], se unific H
1
i H
3
i obinem: L=(1,1,1,1,1,6,7) i
H
1
=(1,2,3,4,5).
Pasul 5:
Muchia [2,3] nu poate fi aleas pentru c ar
crea un ciclu.
Se alege muchia [6,5] i se obine subarborele
H
1
=(1,2,3,4,5,6).
Pasul 6:
Se alege muchia [2,7] si L devine (2,2,2,2,2,2,2), ceea ce corespunde unui arbore parial
de cost minim H=([1,2], [2,5], [3,4], [5,4], [6,5], [2,7]), costul total fiind 12.
Nu are importan care subarbore se alege pentru a transfera vrfurile celuilalt subarbore.
Observaie: Dac exist mai multe muchii cu acelai cost, pentru un graf conex G pot exista mai multe
posibiliti de alegere a unei muchii de cost minim, deci pot exista mai muli APM. Aceti arbori se vor
deosebi prin muchiile ce vor fi luate n consideraie, i nu prin costul asociat, deoarece aceast cost va fi
acelai pentru toi arborii, i anume ei vor avea cost minim.
Implementarea algoritmului lui Kruskal este:
#include<iostream>
#include<fstream>
Using namespace std;
#define N 30
#define M 60
typedef struct {
int x,y;
float cost;
}MUCHIE;
void citire_muchii(MUCHIE u[M],int &n,int &m)
{
int k;
ifstream f(graf.in);
cin>>n>>m;
for(k=1;k<=m;k++)
cin>>u[k].x>>u[k].y>>u[k].cost;
f.close();
}
void sortare(MUCHIE u[M],int m)
{
MUCHIE aux; int i,j;
for(i=1;i<=m-1;i++)
for(j=i+1;j<=m;j++)
if(u[i].cost>u[j].cost)
{
aux=u[i]; u[i]=u[j]; u[j]=aux;
}
}
void creare_apm(MUCHIE u[M],int n,int m)
{
int L[N],k,i,v,w,j;
float ct=0; //cost total apm
for(i=1;i<=n;i++) L[i]=i; //n subarbori disjuncti
i=1; k=0;
cout<<endl<<APM: ";
while(k<n-1)
{
if(L[u[i].x]!=L[u[i].y])
//extremitatile muchiei sunt in subarbori diferiti
{
k++;
ct+=u[i].cost; //adaugam costul muchiei i
cout<<u[i].x<<u[i].y;
v=L[u[i].y]; w=L[u[i].x];
for(j=1;j<=n;j++)
if(L[j]==v) L[j]=w; //reunim cei doi arbori
}
i++; //trecem la urmatoarea muchie
}
cout<<endl<<ncostul total este<<ct;
}
int main()
{
MUCHIE u[M]; int n,m;
citire_muchii(u,n,m); sortare(u,m); creare_apm(u,n,m);
}
Algoritmul lui Prim
Graful conex este dat prin matricea costurilor, forma 1. La fiecare pas k>0 obinem un arbore
H
1
cu k+1 vrfuri i n-(k+1) arbori cu cte un singur vrf. La fiecare pas se alege muchia de cost
minim care are o extremitate n arborele H
1
deja creat i cealalt extremitate liber. Lucrm cu vectorul T
n care vom avea, pentru fiecare vrf neales nc, vrful din H
1
de care acesta se leag printr-o muchie
de cost minim (legtur de tip tat). n componenta corespunztoare din vectorul Q vom avea costul
muchiei adugate. Cum la nceput avem n H
1
doar vrful 1, n toate componentele lui T avem 1, cu
excepia lui T[1], iar n Q, valorile corespunztoare din linia 1 a matricei costurilor c. La pasul k, dup
alegerea unui nou vrf w care se adaug la H
1
, se vor actualiza componentele din T i Q pentru vrfurile
nealese nc deoarece adugarea vrfului w poate modifica aceste valori. Algoritmul are ordinul de
complexitate u(n
2
).
Algoritmul pseudocod corespunztor este:
algoritm Prim(G,c,rad)
QX(G)
pentru fiecare ueQ executa
D[u]
sfarsit pentru
D[rad]0
T[rad]0
cat timp Q=0 executa
uExtrage_Minim(Q)
pentru fiecare vecinilor lui u executa
daca veQ i c(u,v)<D[v] atunci
T[v]u
D[v]c(u,v)
sfarsit daca
sfarsit pentru
sfarsit cat timp
Se iniializeaz vectorul Q astfel nct acesta s conin toate vrfurile grafului i se iniializeaz cmpul D
al fiecrui vrf cu , excepie fcnd rdcina rad, al crei cmp D este iniializat cu 0. Tatl rdcinii se
iniializeaz cu 0, deoarece rad nu are nici un printe. Pe parcursul algoritmului, mulimea X-Q conine
vrfurile arborelui curent. Se identific un vrf ueQ incident unei muchii de cost minim care traverseaz
tietura (X-Q,X) (cu excepia primei iteraii n care u=rad deoarece are cheia D[rad]=0). Eliminarea
lui u din mulimea Q l adaug pe acesta mulimii U-Q a vrfurilor din arbore. n liniile urmtoare se
actualizeaz cmpurile D i T ale fiecrui vrf v adiacent lui u, dar care nu se afl n arbore. Actualizarea
respect condiiile D[v]=c(v,T[v]) i (v,T[v]) s fie o muchie de cost minim care l unete pe v cu
un vrf din arbore.
Fie graful din figura
urmtoare:
Configuraia iniial:
Pasul 1:
Pasul 2:
Pasul 3:
Pasul 4:
Pasul 5:
Pasul 6:
Implementarea algoritmului lui Prim este:
#include<iostream>
using namespace std;
#define N 30
#define M 60
#define INF 1<<14
void citire_graf(int c[N][N],int &n)
{
int m,i,j,x,y,z;
ifstream f(graf.in);
cin>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++) c[i][j]=INF;
for(i=1;i<=n;i++) c[i][i]=0;
for(i=1;i<=m;i++)
{
cin>>x>>y>>z;
c[x][y]=c[y][x]=z;
}
f.close();
}
void creare_apm(int c[N][N],int n)
{
int V[N],T[N],Q[N],i,j,min,w,ct=0; //costul total al arborelui
for(i=1;i<=n;i++) V[i]=i; //varfurile neincluse in arbore
V[1]=0;
for(j=2;j<=n;j++)
{
T[j]=1; Q[j]=c[1][j];
}
cout<<endl<<APM: ";
while(1)
{
min=INF; //determinam muchia de cost minim
for(i=2;i<=n;i++)
if(V[i] && Q[i]<min)
{
min=Q[i]; w=i;
}
if(min==INF) break;
V[w]=0; //varful w a fost inclus in arbore
cout<<T[w]<<w; //muchia adaugata
ct+=c[T[w]][w]; //actualizam costul arborelui
for(j=2;j<=n;j++)
if(V[j] && Q[j]>c[w][j])
{
T[j]=w; Q[j]=c[w][j];
}
}
cout<<endl<<costul total este<<ct;
}
int main()
{
int c[N][N],n;
citire_graf(c,n); creare_apm(c,n);
}