You are on page 1of 34

Arbori de acoperire de cost minim

(Algoritm Kruskal si Prim)

Proiect PCLP III

2009

1
Cuprins

1.Definitii generale 3

2.Arbori partiali de cost minim 4

3. Algoritmul lui Kruskal si Prim (Principii de functionare si limbaj natural) 5

4.Algoritmul lui Kruskal 6-17


4.1Algoritmul lui Kruskal (general) 6- 8
4.2Aplicatii algoritmul lui Kruskal (grafuri conexe) 9-14
4.3Aplicatii algoritmul lui Kruskal(grafuri neconexe) 15
4.4Aplicatie:Reteaua de telefonie nationala 16-17

5.Algoritmul lui Prim 18-25


5.1Algoritmul lui Prim (general) 18-21
5.2 Algoritmul lui Prim implementare in C/C++ 21-25
5.3 Algoritmul lui Prim (exemplu) 26-29

6.Probleme propuse 30-33

7.Bibliografie 34

2
Definitii generale

Ce este un graf ?
• Numim graf o pereche ordonată de mulţimi, notată G=(X,U), unde X este o mulţime
finită şi nevidă de elemente numite noduri sau vârfuri, iar U este o mulţime de perechi
(ordonate sau neordonate) de elemente din X numite muchii (dacă sunt perechi
neordonate) sau arce (dacă sunt perechi ordonate). În primul caz, graful se numeşte
orientat, altfel acesta este neorientat.

• Aşadar un graf poate fi reprezentat sub forma unei figuri geometrice alcătuite din puncte
(care corespund vârfurilor) şi din linii drepte sau curbe care unesc aceste puncte (care
corespund muchiilor sau arcelor).

graf neorientat graf orientat

Ce este un graf ponderat ?


• Un graf ponderat “weighted graph” este un graf în cadrul căruia fiecarui arc îi este
asociată o valoare;

• Valoarea asociată arcului are semnificaţia de “cost” a legăturii între cele 2 noduri sau de
“distanţa” între noduri.

Ce este Arborele de acoperire de cost minim ?


Fie G=(N,A) un graf conex în care fiecare arc are ataşat un cost c(u,v).

Un arbore de acoperire a lui G este arborele liber care:

• cuprinde toate nodurile din N;

• este subgraf a lui G.

Ce este un graf conex ?


• Spunem că un graf este conex dacă între oricare două vârfuri ale acestuia există cel
puţin un drum.

3
Arbori partiali de cost minim
• Fie G = <V, M> un graf neorientat conex, unde V este multimea varfurilor si M este
multimea muchiilor. Fiecare muchie are un cost nenegativ (sau o lungime nenegativa).
Problema este sa gasim o submultime A x M, astfel incat toate varfurile din V sa ramina
conectate atunci cand sunt folosite doar muchii din A, iar suma lungimilor muchiilor din
A sa fie cat mai mica. Cautam deci o submultime A de cost total minim. Aceasta
problema se mai numeste si problema conectarii oraselor cu cost minim, avand
numeroase aplicatii.
• Graful partial <V, A> este un arbore (Exercitiul 6.11) si este numit arborele partial de
cost minim al grafului G (minimal spanning tree). Un graf poate avea mai multi arbori
partiali de cost minim si acest lucru se poate verifica pe un exemplu.
• Vom prezenta doi algoritmi greedy care determina arborele partial de cost minim al unui
graf. In terminologia metodei greedy, vom spune ca o multime de muchii este o solutie,
daca constituie un arbore partial al grafului G, si este fezabila, daca nu contine cicluri. O
multime fezabila de muchii este promitatoare, daca poate fi completata pentru a forma
solutia optima. O muchie atinge o multime data de varfuri, daca exact un capat al
muchiei este in multime. Urmatoarea proprietate va fi folosita pentru a demonstra
corectitudinea celor doi algoritmi.

Proprietatea 6.2 Fie G = <V, M> un graf neorientat conex in care fiecare muchie are un
cost nenegativ. Fie W x V o submultime stricta a varfurilor lui G si fie A x M o multime
promitatoare de muchii, astfel incat nici o muchie din A nu atinge W. Fie m muchia de
cost minim care atinge W. Atunci, A x {m} este promitatoare.
• Demonstratie: Fie B un arbore partial de cost minim al lui G, astfel incat A x B (adica,
muchiile din A sunt continute in arborele B). Un astfel de B trebuie sa existe, deoarece A
este promitatoare. Daca m x B, nu mai ramane nimic de demonstrat. Presupunem ca
m x B. Adaugandu-l pe m la B, obtinem exact un ciclu (Exercitiul3.2). In acest ciclu,
deoarece m atinge W, trebuie sa mai existe cel putin o muchie m' care atinge si ea pe W
(altfel, ciclul nu se inchide). Eliminandu-l pe m', ciclul dispare si obtinem un nou arbore
partial B' al lui G. Costul lui m este mai mic sau egal cu costul lui m', deci costul total al
lui B' este mai mic sau egal cu costul total al lui B. De aceea, B' este si el un arbore partial
de cost minim al lui G, care include pe m. Observam ca A x B' deoarece muchia m', care
atinge W, nu poate fi in A. Deci, A x {m} este promitatoare.

4
Algoritmul lui Kruskal si Prim (Principii de functionare si limbaj natural)

Algoritmul lui Prim (principiu)

– Fie G=(N,A) şi o funcţie de cost definită pe arcele sale;

– Fie U o submulţime a lui N;

– Dacă (u,v) este un arc cu costul cel mai scăzut, a.î. u € U şi v € N\U atunci există
un arbore de acoperire minim care include (u,v).

Algoritmul lui Kruskal (principiu)

– Fie graful G=(N,A)

– La fiecare pas se alege arcul de cost minim;

– Dacă arcul ales nu introduce ciclu în arborele de acoperire minim atunci el se adaugă la
acesta.

Algoritmul lui Prim (limbaj natural)

1. Introducem un nod arbitrar în U.

2. Selectăm arcul de cost minim (u,v) care conectează mulţimea U cu N\U, u<U,v<N\U.
Adăugăm acest arc arborelui.

3. Dacă U!=N executăm pasul 2.

5
Algoritmul lui Kruskal

Algoritmul lui Kruskal este un algoritm în teoria grafurilor care găseşte arborele parţial de cost
minim pentru un graf conex ponderat. Cu alte cuvinte, găseşte submulţimea muchiilor care
formează un arbore care include toate vârfurile şi care este minimizat din punct de vedere al
costului. Dacă graful nu este conex, atunci algoritmul găseşte o pădure parţială de cost minim
(un arbore parţial de cost minim pentru fiecare componentă conexă). Algoritmul lui Kruskal este
un exemplu de algoritm greedy.

Algoritmul funcţionează în felul următor:

 creează o pădure F (o mulţime de arbori), unde fiecare vârf din graf este un arbore
separat
 creează o mulţime S care conţine toate muchiile din graf
 atât timp cât S este nevidă
o elimină o muchie de cost minim din S
o dacă acea muchie conectează doi arbori distincţi, atunci adaugă muchia în pădure,
combinând cei doi arbori într-unul singur
o altfel, ignoră muchia

La sfârşitul algoritmului, pădurea are doar o componentă care reprezină un arbore parţial de cost
minim al grafului.

Acest algoritm a fost scris de Joseph Kruskal, în 1956.

Exemplu:

Acesta este graful original. Numerele de pe muchii reprezintă


costul acestora. Nici o muchie nu este evidenţiată.

6
AD şi CE sunt cele mai scurte muchii, de cost 5, iar AD a fost
arbitrar aleasă, deci este evidenţiată.

CE este muchia de cost minim care nu formează un ciclu, deci


este evidenţiată.

Următoarea muchie, DF, de cost 6, este evidenţiată în acelaşi


fel.

Următoarele muchii de cost minim sunt AB şi BE, de cost 7.


AB este aleasă arbitrar şi este evidenţiată. Muchia BD este
marcată cu roşu, deoarece ar forma ciclul ABD dacă ar fi
aleasă.

7
Procesul continuă cu evidenţiarea următoarei muchii, BE, de
cost 7. Mai multe muchii sunt marcate cu roşu la acest pas: BC,
deoarece ar forma ciclul BCE, DE, deoarece ar forma ciclul
DEBA şi FE deoarece ar forma ciclul FEBAD.

În sfârşit, procesul se încheie cu muchia EG de cost 9, iar


arborele parţial de cost minim este găsit.

Pseudocod
1) function Kruskal(G)
2) for each vârf v în G do
3) Defineşte un grup elementar C(v) ← {v}.
4) Creează o coadă cu priorităţi Q care conţine muchiile din G, având costul drept cheie.
5) Defineşte un arbore T ← Ø //T va conţine în final toate muchiile din APCM
6) // n este numărul total de vârfuri
7) while T are mai puţin de n-1 muchii do
8) // muchia u,v este drumul minim de la u la v
9) (u,v) ← Q.eliminăMin()
10) Fie C(v) grupul care îl conţine pe v şi C(u) grupul care îl conţine pe u.
11) if C(v) ≠ C(u) then
12) Adaugă muchia (v,u) la T.
13) Uneşte C(v) şi C(u) într-un grup, adică reuniune între C(v) şi C(u).
14) return arborele T

8
Aplicatii algoritmul lui Kruskal

(grafuri conexe)

Cazurile cele mai simple sunt cele ale grafurilor conexe, adica acelea in care din orice
nod se poate ajunge in orice alt nod

In figura de mai jos este prezentat un graf neconex alcatuit din 2 componente conexe,
care n-au legatura una cu alta

Cu alte cuvinte, in graful de mai jos nu se poate ajunge din orice nod in orice alt nod
(daca nodurile sunt in componente conexe diferite)

Pentru un graf conex pot fi gasiti mai multi arbori de acoperire, in functie de arcele care
sunt alese pentru a forma arborele

Costul total al arborelui de acoperire este dat de suma costurilor arcelor alese, deci vom
avea arbori “mai scumpi” si arbori “mai ieftini”

Algoritmul lui Kruskal gaseste arborele de acoperire cel mai ieftin pentru un graf conex
ponderat, pe care-l vom numi “arborele de acoperire minim” (acesta poate sa nu fie unic)

Daca graful nu este conex, el este alcatuit din subgrafuri (componente) conexe

In cazul unui astfel de graf, algoritmul lui Kruskal gaseste cate un arbore de acoperire
minim pentru fiecare componenta conexa a grafului (neconex) dat, adica o “padure de
arbori de acoperire minimi”

Se lucreaza cu mai multe multimi de noduri

Initial, se porneste de la N multimi a cate un nod, astfel incat fiecare nod al grafului sa
faca parte din cate o multime (N este numarul de noduri din graf)

9
La fiecare pas se selecteaza cel mai ieftin arc din graf care conecteaza noduri din
multimi diferite

Daca un astfel de arc nu exista, algoritmul se incheie

Dupa selectia arcului, cele doua multimi din care fac parte extremitatile sale se inlocuiesc
cu reuniunea lor, numarul total de multimi scazand cu o unitate

Consecinta este ca algoritmul se va opri atunci cand numarul de multimi ajunge egal cu
numarul de componente conexe ale grafului (o singura multime in cazul grafurilor
conexe)

Exemplu

Fie graful din figura :cel mai ieftin arc din graf care leaga noduri din multimi diferite este
D-H de cost 1

Multimile sunt in numar de 8:

{A} {E}

{B} {F}

{C} {G}

{D} {H}

Sunt 3 arce viabile: A-B, D-G si G-H

Se alege arbitrar arcul A-B

10
Multimile sunt in numar de 7:

{A} {E}

{B} {F}

{C} {G}

{D, H}

Arcul G-H, desi cel mai ieftin din graf, este ignorat, deoarece uneste noduri din aceeasi
multime si se alege arcul A-D

Multimile sunt in numar de 5:

{A, B} {E}

{C} {F}

{D, G, H}

11
Se alege arcul C-F

Multimile sunt in numar de 4:

{A, B, D, G, H} {E}

{C} {F}

Se alege arcul B-E

Multimile sunt in numar de 3:

{A, B, D, G, H} {E}

{C, F}

12
Se alege arcul F-H

Multimile sunt in numar de 2:

{A, B, D, E, G, H} {C, F}

13
Algoritmul se incheie deoarece nu se mai poate gasi un arc care conecteaza noduri din
multimi diferite (fiind o singura multime)

Arborele de acoperire este cel din figura de mai jos, costul sau fiind 19

Nu exista un arbore de acoperire mai ieftin pentru graful dat

Multimile sunt in numar de 1:

{A, B, C, D, E, F, G, H}

Conditia de oprire a algoritmului este imposibilitatea gasirii unui arc care conecteaza
noduri din multimi diferite

Aceasta conditie este indeplinita implicit atunci cand s-a ajuns la o singura multime

Daca graful nu este conex, atunci nu se va ajunge niciodata la o singura multime

Totusi, cand numarul de multimi ajunge egal cu numarul de componente conexe din graf
(>1 pentru un graf neconex), atunci nu se mai poate gasi un arc care conecteaza noduri
din multimi diferite, deci algoritmul se incheie in conformitate cu conditia de oprire
enuntata

14
Aplicatii algoritmul lui Kruskal

(grafuri neconexe)
Aplicand algoritmul lui Kruskal pentru graful neconex din figura, se ajunge in situatia
prezentata: 2 arbori de acoperire (o padure), cate unul pentru fiecare componenta conexa
a grafului

Multimile sunt: {A, B, C, E} {D, F, G, H} – 2 multimi, tot atatea cate componente


conexe are graful

Prin insasi natura neconexa a grafului, algoritmul nu mai poate gasi nici un arc (cu atat
mai mult nu poate gasi un arc minim) care conecteaza noduri din multimi diferite

Daca un astfel de arc ar exista, graful nu ar fi neconex, ci acel arc ar fi legatura intre cele
doua grupuri de noduri care formeaza acum cele doua componente conexe ale grafului

Neexistand arcul necesar continuarii algoritmului, acesta se opreste si rezultatul este dat
de arcele ingrosate din figura de pe slide-ul anterior

15
Aplicaţie: Reteaua de telefonie nationala

( Timisoara-Arad-Bucuresti)
Trebuie sa conectam 3 orase la o retea telefonica: Bucuresti, Timisoara si Arad

Necesar cablu: 1300 km

E inutil sa executam toate cele trei conexiuni, numai doua din ele sunt suficiente pentru o
comunicare in bune conditii intre oricare 2 orase

De exemplu, legatura Timisoara – Arad ar putea lipsi, caz in care necesarul de cablu
devine 1240 km

Sau legatura Timisoara – Bucuresti ar putea lipsi, necesarul de cablu devenind 700 km

16
Oricare 2 legaturi sunt suficiente, deoarece semnalul electric circula suficient de rapid ca
un abonat din Timisoara care doreste sa vorbeasca cu unul din Arad (de exemplu) sa nu-
si dea seama ca nu exista legatura directa intre Timisoara si Arad si ca apelul sau este
rutat prin Bucuresti

Din punctul de vedere al necesarului de cablu, lucrurile nu mai stau la fel

Conteaza foarte mult care legaturi vor fi realizate si care nu

Cel mai ieftin ar fi sa alegem legaturile Arad – Timisoara si Timisoara – Bucuresti si sa


evitam legatura Arad - Bucuresti, necesarul de cablu ajungand in acest caz la 660 km;
aceasta este situatia optima – sau “acoperirea minima” a retelei

Se observa ca trebuie determinat un arbore de acoperire pentru graful initial, adica un


subgraf continand toate nodurile grafului insa doar atatea arce cat sa ramana un arbore
(trebuie evitate ciclurile)

Pentru un graf conex cu N noduri, un arbore de acoperire va avea N-1 arce (2 arce in
cazul grafului Arad – Timisoara – Bucuresti discutat)

17
Algoritmul lui Prim
Este un algoritm din teoria grafurilor care găseşte arborele parţial de cost minim al unui graf
conex ponderat. Înseamnă că găseşte submulţimea muchiilor care formează un arbore care
include toate vârfurile şi al cărui cost este minimizat. Algoritmul a fost descoperit în 1930 de
către matematicianul Vojtěch Jarník şi apoi, independent, de informaticienii Robert C. Prim în
1957 şi redescoperit de Edsger Dijkstra în 1959. De aceea mai este numit Algoritmul DJP,
algoritmul Jarník sau algoritmul Prim-Jarník.

Descriere

Algoritmul incrementează mărimea unui arbore, pornind de la un nod, până când sunt incluse
toate nodurile.

 Intrare: Un graf conex ponderat cu nodurile V şi muchiile E.


 Initializare: Vnou = {x}, unde x este un nod arbitrar (punct de plecare) din V, Enou= {}
 repetă până când Vnou=V:
o Alege muchia (u,v) din E de cost minim astfel încât u este în Vnou şi v nu e (dacă
există mai multe astfel de muchii, se alege arbitrar)
o Se adaugă v la Vnou, (u,v) la Enou
 Ieşire: Vnou şi Enou descriu arborele parţial de cost minim

Exemplu

Mulţimea
Imagine Descriere Nevizitate Vecini
soluţie

Acesta este graful ponderat


original. Nu este un arbore
pentru că din definiţia
arborelui se cere să nu
A, B,
existe cicluri. Numerele de C, G D
E, F
pe muchii reprezintă costul.
Nici un arc nu e evidenţiat,
iar nodul D a fost ales
arbitrar ca punct de plecare.

18
Al doilea nod ales este unul
din vecinii lui D: A se află
la distanţa 5, B la 9, E la 15
B, E,
şi F la 6. Dintre acestea, 5 C, G A, D
F
este cel mai mic cost, deci
se evidenţiază nodul A şi
muchia DA.

Următorul nod ales este


unul din vecinii lui D sau A.
B se află la distanţa 9 de D
B, E,
şi la 7 de A, E la 15 şi F la C A, D, F
G
6. 6 este cel mai mic, deci se
evidenţiază nodul F şi
muchia DF.

Nodul B, care e la distanţa 7


de A, este evidenţiat. Aici,
muchia DB este evidenţiată
C, E,
cu roşu, deoarece ambele null A, D, F, B
G
noduri B şi D au fost deja
evidenţiate, deci nu poate fi
folosită.

În acest caz, putem alege


între C, E şi G. C este la 8
faţă de B, E este la 7 de B şi
G la 11 faţă de F. E se află
cel mai aproape, deci se A, D, F,
null C, G
evidenţiază nodul E şi B, E
muchia EB. Alte două
muchii au fost marcate cu
roşu, deoarece nodurile lor
au fost deja vizitate.

19
Aici sunt disponibile doar
nodurile C şi G. C se află la
distanţa 5 de E, iar G la 9 de
A, D, F,
E. C este ales, deci este null G
B, E, C
evidenţiat împreună cu
muchia EC. Muchia BC
este marcată cu roşu.

Nodul G este singurul


rămas. Se află la distanţa 11
faţă de F şi la 9 faţă de E. E
este mai aproape, deci se
evidenţiază muchia EG. Au A, D, F,
null null
fost incluse toate vârfurile, B, E, C, G
deci arborele parţial de cost
minim este evidenţiat cu
verde. În acest caz, are
costul 39.

[Iniţializare

intrare: Un graf, o funcţie care returnează costul muchiilor şi un nod iniţial r

plasează toate nodurile în mulţimea celor nevizitate, adaugă nodul iniţial la arbore şi plasează
toate nodurile într-un min-heap.

for fiecare v in graf


distanţăMin [v] ← ∞
părinte [v] ← -1
listaDeAdiac [v] ← mulţimeaVidă
înQ [v] ← true
distanţă [r] ← 0
Q←V

Algoritm:În descrierea algoritmului de mai sus,


nodProxim este Q[0], acum ultim
vecini este v din Q unde distanţa faţă de v < ∞, după ce vârful proxim este eliminat
nevizitat este v din Q unde distanţa faţă de v = ∞, după ce vârful proxim este eliminat

20
Bucla while se va termina când nu mai există noduri care pot fi returnate.

complexitate în timp: V pentru buclă, log(V) pentru eliminare


while ultim ← eliminăMin(Q)
înQ [ultim] ← false
adaugă ultim la listaDeAdiac [părinte [ultim]]
adaugă părinte [ultim] la listaDeAdiac [ultim]

complexitate în timp: E/V, numărul mediu de noduri


for each adiacent al lui ultim
if (înQ [adiacent]) şi (cost(ultim, adiacent) < distanţăMin [adiacent])
părinte [adiacent] ← ultim
distanţăMin [adiacent] ← cost(ultim, adiacent)

complexitate în timp: log(V), înăţimea heap-ului


update adiacent în Q, ordonează după distanţăMin

21
Algoritmul lui Prim implementare in C/C++

#include<stdio.h>

#include<conio.h>

#include<values.h>

#include<math.h>

int N,E,i,j,k,x,y,l,min,cost[20][20],tr[20][2],mincost=0,nears[20];

int u,v,c;

void read_from_file(void);

int findmin(void);

FILE *fp;

main()

clrscr();

fp=fopen("graph.txt","r");

fscanf(fp,"%d%d",&N,&E);

min=MAXINT;

read_from_file();

tr[0][0]=k;

tr[0][1]=l;

for(i=1;i<=N;++i)

if(cost[i-1][l-1]<cost[i-1][k-1])

nears[i]=l;

22
else

nears[i]=k;

nears[l]=0;

nears[k]=0;

for(i=1;i<N-1;++i)

j=findmin();

tr[i][0]=j;

tr[i][1]=nears[j];

mincost=mincost+cost[j-1][nears[j]-1];

nears[j]=0;

/* update nears[] */

for(k=1;k<=N;++k)

if(nears[k]!=0 && cost[k-1][nears[k-1]] > cost[k-1][j-1])

nears[k]=j;

for(i=0;i<N-1;++i)

printf("%d %d \n",tr[i][0],tr[i][1]);

printf("Minimum cost = %d",mincost);

fclose(fp);

23
getch();

void read_from_file(void)

for(i=0;i<N;++i)

for(j=0;j<N;++j)

cost[i][j]=MAXINT;

for(i=1;i<=E;++i)

fscanf(fp,"%d%d%d",&u, &v, &c);

cost[u-1][v-1]=c;

cost[v-1][u-1]=c;

if(min>c)

min=c;

k=u;

l=v;

mincost=min;

24
int findmin(void)

min=MAXINT;

for(x=1;x<=N;++x)

if(nears[x]!=0 && cost[x-1][nears[x]-1]<min)

min=cost[x-1][nears[x]-1];

y=x;

return y;

25
Algoritmul lui Prim (Exemplu)

Etape de parcurgere:

1.U={1}; N\U={2,3,4,5,6,7}

2. U={1,2}; N\U={3,4,5,6,7}

3. U={1,2,3}; N\U={4,5,6,7}

4.U={1,2,3,5}; N\U={4,6,7}

5.U={1,2,3,4,5}; N\U={6,7}

6.U={1,2,3,4,5,6}; N\U={7}

7.U={1,2,3,4,5,6,7}; N\U=ø

Functionarea algoritmului, pentru exemplul de mai jos este ilustrata in Tabelul 1. La sfarsit, A va
contine aceleasi muchii ca si in cazul algoritmului lui Kruskal.

Pasul Muchia considerata W


Initializare — {1}
1 {2, 1} {1, 2}
2 {3, 2} {1, 2, 3}

26
3 {4, 1} {1, 2, 3, 4}
4 {5, 4} {1, 2, 3, 4, 5}
5 {7, 4} {1, 2, 3, 4, 5, 6}
6 {6, 7} {1, 2, 3, 4, 5, 6, 7}
Tabelul 1 Algoritmul lui Prim aplicat grafului din Figura 6.1a.

Descrierea algoritmului este data in continuare.

Pentru a obtine o implementare simpla, presupunem ca: varfurile din X sunt numerotate de la 1 la
n, X = {1, 2, ..., n}; matricea simetrica C da costul fiecarei muchii, cu C[i, j] = maxint, daca
muchia {i, j} nu exista. Folosim doi vectori,vectorul parintilor T[i] si un vector s[i].

Vectorul T este vectorul tata in care ,pentru fiecare nod i din X,T[i] este egal cu parintele lui i.

Vectorul S este definit astfel:

S[i]= 0 daca i apartine arborelui partial construit pana atunci

K daca :- i nu apartine arborelui partial deja construit

-muchia de cost minim care uneste i cu un nod din graful deja construit este [i,k]

cu k neapartinand arborelui partial

Initial vectorul tata este 0 peste tot iar vectorul S este definit astfel:S[v]=0 si S[i]=v pentru
i<>v,unde v este varful arborelui.Se alege apoi muchia de cost minim (i,j) care are numai o
extremitate in arborele partial construit adica S[i]=0 iar S[j]<>0.Se reactualizeaza cei doi
vectori:vectorul S pentru j adica S[j]=0 iar vectorul tata T[j]=S[j].Se reia cautarea muchiei de
cost minim daca nu au fost alese n-1 muchii.

Aplicand acest algoritm pentru graful din Figura 2.a,se vor urma pasii:

-n=5,a matricea de cost si varful

-se alege varful,de exemplu v=1 iar vectorii sunt:

0 1 1 1 1

0 0 0 0 0

27
-si ia i=2,n si se alege muchia de cost minim determinata de a[i,S[i]],(in acest caz se alege j=2).

-se reactualizeaza vectorii T si S;T[j]=S[j](T[2]=1) si S comparandu-se valoarea muchiei [i,S[i]]


cu

cea a muchiei [i,j] si daca este mai mica se modifica S(S[i]=j) unde S[i]<>0 si j este ultimul varf
introdus.Cei doi vectori vor fi:

0 0 2 2 1

0 1 0 0 0

-se cauta din nou muchia de cost minim si se repeta faza precedunta pana se aleg n-1 muchii(in
cazul Figurii 2.a, 4 muchii).Vectorii vor suferii urmatoarele transformari:

1. S

0 0 4 0 1

0 1 0 2 0

. 2. S

0 0 4 0 0

0 1 0 2 1

3. S

0 0 0 0 0

0 1 4 2 1

-in final vectorul S va fi zero iar vectorul T va fi vectorul tata a arboreluipartial de cost
minim.Costul arborelui(Figura 2.b) va fi 10.

28
Se cere sa se dea varful dar aceste poate fi luat intotdeauna 1 daca se cauta sa se afle numai
costul arborelui deoarece,muchiile nefiind orientate, se obtine intotdeauna acelasi arbore.Cel ce
difera este insa vectorul tata in funtie de varful de pornire dar acesta poate fi refacut dupa
vectorul tata al grafului ce are varful 1.

29
Probleme Propuse(Arbori de cost minim)

Problema 1:

Se da un graf conex neorientat G cu N noduri si M muchii, fiecare muchie avand asociat un cost.
Se cere sa se determine un subgraf care cuprinde toate nodurile si o parte din muchii, astfel incat
subgraful determinat sa aiba structura de arbore si suma costurilor muchiilor care il formeaza sa
fie minim posibila. Subgraful cu proprietatile de mai sus se va numi arbore partial de cost minim
pentru graful dat.

Date de intrare

Fisierul de intrare apm.in va contine pe prima linie numerele N si M, separate printr-un spatiu. Pe
urmatoarele M linii se vor gasi muchiile grafului sub forma X Y C, cu semnificatia ca exista
muchie neorientata intre X si Y de cost C.

Date de ieșire

Fisierul de iesire apm.out va contine pe prima linie costul arborelui partial de cost minim. Pe a
doua linie se va gasi numarul de muchii din arborele partial selectat. Fiecare din urmatoarele
linii, pana la sfarsitul fisierului de iesire, va contine cate doua numere naturale, capetele unei
muchii ce apartine arborelui solutie. Muchiile pot fi afisate in orice ordine. Daca sunt mai multe
solutii corecte se poate afisa oricare.

Restrictii

 1 ≤ N ≤ 200 000
 1 ≤ M ≤ 400 000
 -1 000 ≤ C ≤ 1 000
 Pentru 20% din teste N, M ≤ 20
 Pentru inca 20% din teste N ≤ 800 si M ≤ 1 500

Exemple

apm.in apm.out apm.in apm.out


9 14
37
1 2 10
8
1 3 -11
31
2 4 11
79 33 -9
2 5 11
73 1 2 -3 2
5 6 13
98 2 3 -4 1 3
3 4 10
74 3 1 -5 3 2
4 6 12
21
475
52
374
76
385

30
875
894
973
6 7 11

Explicatii

Exemplul 1: Un arbore partial de cost minim pentru graful dat poate fi format din urmatoarele
muchii: (7, 3), (7, 4), (7, 9), (7, 6), (9, 8), (1, 3), (1, 2) si (2, 5). Suma costurilor acestor muchii
este 37. Solutia nu este neaparat unica.

Exemplul 2: Desi solutia optima ar parea la prima vedere introducerea tuturor celor 3 muchii,
acest lucru nu este posibil deoarece s-ar crea un ciclu. Vor fi selectate muchiile (2, 3) si (3, 1).

Indicatii de rezolvare

O prima idee ar fi generarea tuturor submultimilor de N-1 muchii, verificarea daca muchiile
selectate formeaza un arbore si retinerea solutiei optime. Aceasta rezolvare este cea mai evidenta
dar are complexitate exponentiala si obtine aproximativ 20 de puncte.
Presupunand ca sunt deja alese N-2 muchii care nu formeaza cicluri, in alte cuvinte formeaza 2
arbori, trebuie sa se mai aleaga inca o muchie, si anume muchia minima care garanteaza
conectivitatea arborilor. De la aceasta idee deducem ca cel mai bine ar fi sa adaugam muchii de
cost minim, cat timp aceste muchii nu creaza cicluri.
Daca se sorteaza muchiile crescator dupa costul asociat si se parcurg in ordinea sortarii, este
mereu util sa adaugam la solutie muchia de cost minim cat timp aceasta nu creaza un ciclu, sau
altfel spus, nodurile pe care le uneste nu sunt deja in aceeasi componenta conexa. Aceasta solutie
are complexitate O(N*M + Mlog2M), deoarece iterarea prin cele M muchii are complexitate
O(M), iar parcurgerea dfs pentru verificarea ciclurilor se realizeaza in timp O(N) la fiecare pas. O
astfel de solutie obtine 40-50 de puncte, in functie de implementare, si se poate vedea aici.
Pentru a optimiza solutia de mai sus este suficient la fiecare pas sa verificam daca cele doua
noduri pe care le uneste muchia curenta sunt in aceeasi componenta conexa, operatie care se
poate realiza in timp O(log*N), cu ajutorul multimilor disjuncte. Astfel complexitatea se reduce
la O(Mlog*N + Mlog2M). Acest algoritm este prezentat si aici si se numeste algoritmul lui
Kruskal. O implementare pe aceasta idee se gaseste aici.
Pentru a intelege o alta solutie se presupune urmatorul scenariu: existand deja calculat un
subarbore minim vrem sa introducem in el inca un nod. Evident vom introduce nodul care are
muchia de cost minim care il leaga de subarborele deja format. Aceasta solutie are complexitate
O(N*M), deoarece incepem cu un nod aleator si adaugam rand pe rand toate nodurile ramase.
Acest algoritm se poate optimiza, daca pentru fiecare nod se tine muchia minima curenta care il
leaga de subarborele existent. La fiecare introducere a unui nod in subarbore, se actualizeaza toti
vecinii lui. Aceasta solutie are complexitate O(N2) si ar trebui sa obtina 50 puncte. Trebuie in
plus precizat ca in cazul in care graful este dens (numarul de muchii M este de ordinul O(N2))
aceasta abordare este de preferat celor cu alte complexitati.
Pentru a se optimiza mai departe algoritmul pentru extragerea minimului se foloseste un heap, iar
de fiecare data cand se introduce un nod in subarbore sunt parcurse muchiile incidente cu el si se

31
actualizeaza nodurile vecine. Astfel complexitatea devine O(M*log2N). Algoritmul este cunoscut
in literatura de specialitate ca Algoritmul lui Prim. O sursa pe acesta idee se poate vedea aici.

Problema 2:

Se dau n orase.Se cunoaste distanta dintre oricare doua orase.Un distribuitor de carte cauta sa-si
faca un depozit in unul dintre aceste orase.Se cere sa se gaseasca traseul optim de la depozit catre
celelalte orase astfel incat distanta totala pe care o va parcurge pentru a distribui in toate celelalte
n-1 orase sa fie minima.sa se precizeze care ar fi orasul in care sa se afle depoitul pentru ca toate
celelalte orase sa fie usor accesibile{din acel centru de depozitare sa se poata pleca sper cat mai
multe alte orase}.

Date se citesc dintr-un fisier astfel:

-pe prima linie numarul de orase

-pe urmatoarele linii traseele existente astfel:orasul din care pleaca,orasul in care ajunge si
distanta in km a drumului.

{Deoarece vor exista foarte multe trasee algoritmul lui Prim este mai bun.Fiind un graf
neorientat se poate pleca cu varful 1.Pentru a afla care ar fi orasul optim vedem inarbore care
este nodul cu cei mai multi fii si refacem vectorul tata.}

Problema 3:

Se da un graf neorientat.Sa se creeze un arbore partial de cost minim care sa poata fi memorat
apoi sub forma unei liste.

Exemplu:

1/1/1 2 1 2/4/2/4/2/6 7/3 4 3 4/5/3/5/3

{Se foloseste algoritmul lui Prim iar pentru fiecare nou nod introdus se verifica daca parintele
sau{s[i]} are mai un fiu sau cel mult unul in cazul in care este chiar varful.Daca sunt indeplinite
aceste conditii se adauga varful la arbore ,daca nu se aplica algoritmul lui prim pentru o noua
matrice A1.Matricea A1 se obtine din A punand costul mechiei care era minima in A egala cu
0.Se repeta procesul pana s-au introdus n-1 varfuri}

Problema 4:

Se da un graf orientat si se cere sa se afle daca exista un arbore partial de cost minim.Dar o
arborescenta de cost minim?Daca exista sa se afle care este este varful acesteia.

32
{Daca exista sau nu o arbore de cost minim se poate spune foarte usor daca verificam
conexitatea grafului.Daca graful este tare conex atunci putem spune ca exista un arbore partial de
cost minim.Un lant de la x la y va avea costul egal cu costul drumui de la x la y plus costul
drumului de la y la x.Pentru a verifica daca exista o arborescenta aplicam unul din cei doi
algoritmi.Daca,in cazul lui Prim,exista si un alt nod cu t[i]=0 cu exceptia varfului atunci aceasta
nu este arborescenta iar in algoritmul Kruskal,daca multimea B a muchiilor are mai putin de n-1
muchii, atunci nu exista arborescenta.Se aplica algoritmii de n ori pentru fiecare nod drept varf
pentru a vedea daca exista o arborescenta de cost minim.Muchiile vor fi orientate iar matricea
costurilor nu va fi simetrica},program arborescent {afiseaza arborescenta in cazul in care exista
una}

Problema 5:

Se da un graf conex.Se cere impartirea acestuia in m arbori partiali de cost minim fiecare cu p
varfuri.Sa se afiseze acesti arbori.

{Cel mai favorabil ar fi algoritmul lui Prim.Acesta se aplica de m ori iar for din procedura va fi
de la 1 la p-1.Nodurile care au fost incluse intr-un arbore precedent vor fi trecute in vectorii S si
T cu valoarea –1 iar matricea va fi zero pe liniile si coloanele respective.}

33
Bibliografie

1.R.D. Vatavu, Proiectarea algoritmilor 2008

2.Knuth D. E., Tratat de programarea calculatoarelor, vol. I, II, III 1973

3.T.H. Cormen, C.E. Leiserson, R.L. Rivest. Introducere in Algoritmi 2000

4.V. Cristea, I. Athanasiu, E. Kalisz, V. Iorga, Tehnici de programare 1998

5.Negrescu L., Limbajul C si C++ 1997

6.Georgescu H., Livovschi L., Analiza si sinteza algoritmilor 1986

7.Ionescu C., Zsako I., Structuri arborescente 1990

8.Horowitz E., Fundamentals of Programming Languages 1983

9.Internet

34