Sunteți pe pagina 1din 18

34

Arbori [i arborescen]e

Proprietăţi elementare ale arborilor

Definiţie: Un arbore este un graf conex şi fără circuite.

Teorema 1. Fie G=(V,E) un graf. Următoarele afirmaţii sînt echivalente:


(i) G este arbore.
(ii) G este conex şi este minimal cu această proprietate.
(iii) G este fără circuite şi este maximal cu această proprietate.

Observaţie: Maximalitatea şi minimalitatea din condiţiile (i) şi (ii) se referă


la mulţimea muchiilor grafului G şi se consideră în raport cu relaţia de ordine dată
de incluziune. Mai precis, cele două afirmaţii se pot formula echivalent astfel:

(ii') G este conex şi ∀e∈E(G), G-e este neconex.


(iii') G este fără circuite şi ∀e∈E( G ), G+e are un circuit.

Demonstraţia teoremei 1: Demonstrăm i) ⇔ ii) şi i) ⇔ iii).


i) → ii) Dac\ G este arbore rezultă că G este conex. Fie e = vw ∈ E(G)
oarecare. Dacă G - e ar fi conex, atunci în G - e există un vw-drum P care impreună
cu vw induc în G un circuit contrazicând faptul că G este arbore. Deci ∀e∈E(G), G
- e este neconex, adic\ ii) are loc.
ii) → i) Trebuie să demonstrăm că G nu are circuite. Presupunând, prin
reducere la absurd, că G are un circuit C şi e = uv ∈ E(C) atunci graful G - e este
conex. În adevăr, oricare ar fi P un drum în G, dacă e∈ E(P) atunci P este drum în
G - e, iar dacă e ∈ E(P), atunci substituind e în P cu drumul C - e se obţine un mers
în G - e cu aceleaşi extremităţi ca şi P, din care se poate extrage un drum cu
aceleaşi extremitaţi ca şi P. Cum G este conex, rezultă din această observaţie că G -
e este conex contrazicând ii).
i) → iii) Trebuie dovedit că ∀e∈E( G ), G + e are un circuit. Evident, putem
presupune că G ≠ K1, K2 (situaţie în care iii are loc întrucât E( G )=0). Fie e = uv ∈
E( G ). Din conexiunea lui G rezultă că există un uv-drum P în G. Atunci P
împreună cu e generează un circuit în G + e.
iii) → i) Trebuie dovedit că G este conex. Dacă, prin reducere la absurd, n-ar
fi aşa, atunci consderând u,v în componente conexe diferite ale lui G, rezultă că uv
∈ E( G ) şi deci conform condiţiei iii), G + uv conţine un circuit C. Dar atunci C - uv
este un uv - drum în G contrazicând alegerea celor două vârfuri.
35

Definiţie: Fie G=(V, E) un (multi) graf. Se numeşte arbore parţial al lui G, un


graf parţial T = (V, E’)(E’ ⊆ E) care este arbore. Vom nota cu TG mulţimea arborilor
parţiali ai lui G.

Observaţie: TG ≠ 0 dacă şi numai dacă G este conex.


În adevăr, dacă TG ≠ 0, atunci există un arbore parţial T=(V, E’) al lui G. T
este conex, deci între orice două vârfuri ale lui G există un drum cu muchii din
E’ ⊆ E. Prin urmare G este conex.
Reciproc, dacă G este conex, atunci considerăm următorul algoritm:

1. T:= G
2. while ( ∃ e ∈ E(T) astfel încât T \ {e} este conex) do
T := T \ {e}

Graful T obţinut este graf parţial al lui G, este conex (din ipoteză, după
atribuirea din 1, aşa este şi din condiţia lui while, T este conex după fiecare
iteraţie) şi în plus la oprirea algoritmului, T satisface condiţia ii) din teorema 1,
deci este arbore.

O altă demonstraţie a reciprocei anterioare se bazează pe observaţia că G =


(V, E) este conex dacă şi numai dacă oricare ar fi o partiţie (V1, V2) a lui V există e =
v1v2 ∈ E cu vi ∈Vi i= 1,2 .
Dacă |V| = n > 0 atunci următorul algoritm construieşte un arbore parţial al
lui G.
begin
1. T1:=( {v},0)(v∈V, oarecare); k:=1;
2. while k<n do begin
Determină v1v2 ∈ E cu v1 ∈V(Tk), v2∈V\V(Tk);
{ există o astfel de muchie din conexiunea lui G }
V(Tk+1) := V(Tk) ∪ {v2};
E(Tk+1) := E(Tk) ∪ {v1v2};
k :=k+1;
end
end.
Se observă că Tk este arbore ∀k = 1, n (inductiv, dacă Tk este arbore, atunci
din construcţie Tk+1 este conex şi nu are circuite), şi în plus se verifică imediat că
|V(Tk)| = k iar |E(Tk)| = k-1 ∀ k=1, 2, . . . , n.
Această demonstraţie aplicată unui arbore G cu n vârfuri dovedeşte că G
36

are n - 1 muchii. Această proprietate poate fi folosită pentru completarea teoremei


1 cu alte caracterizări ale arborilor:

Teorema 1’. Următoarele afirmaţii sunt echivalente pentru un graf G = (V, E) cu n


vârfuri.
(i) G este arbore.
(ii) G este conex şi are n-1 muchii.
(iii) G este fără circuite şi are n-1 muchii.
(iv) G = Kn pentru n = 1, 2 şi G ≠ Kn pentru n ≥ 3 şi adăugarea unei muchii la G
produce exact un circuit.

Demonstraţia teoremei 1’ este la fel de simplă ca cea a teoremei 1 şi o


omitem ( ii ⇒ iii se bazeză pe existenţa unei muchii cu extremităţile în clase
diferite ale oricărei partiţii ale mulţimii vârfurilor unui graf conex; considerând
una din clase mulţimea vârfurilor unui circuit şi repetând observaţia precedentă se
obţine că G are măcar n muchii, contradicţie).

Numărarea şi enumerarea arborilor parţiali

Familia TG a arborilor parţiali ai unui (multi)graf are proprietăţi interesante.


Vom prezenta o metodă (tip backtrak) de generare a elementelor lui TG, problemă
de interes practic în multe aplicaţii (de exemplu, în chimie).
Fie G = (V, E), V= {1, 2, . . . , n}, |E|=m. Considerăm că E este dată printr-un
tablou E = array [1...m, 1..2] of V unde, dacă v= E[i,1] şi w=E[i, 2] , atunci vw este
muchia i a grafului G (i= 1, m ). Vom presupune în plus, că primele dG(v0) muchii
din tabloul E satisfac E[i,1] = v0 unde v0∈V este un vârf oarecare.
Un arbore parţial T∈ TG va fi identificat cu mulţimea indicilor ce reprezintă
muchiile sale în tabloul E (submulţime a lui {1, . . . , m}de cardinal n-1). Pe tot
parcursul generării dispunem de un tablou global T = array[1..n - 1] of 1..m şi de
un indicator i având semnificaţia: în arborele curent care se construieşte, primele i
- 1 muchii sunt

T[1]<T[2]< . . . <T[i-1] (i∈{1, . . . ,n}).


procedure generare-arbori-parţiali(i : integer);
{ se generează toţi arborii parţiali ai lui G
având drept prime i - 1 muchii elementele T(1), . . . , T(i-1)
ale tabloului E (ordonate crescător) }
var j : 1..m; S: listă de vârfuri; x : V;
begin
if i = n then begin
{T(1), . . . , T(n - 1) formează un
37

arbore parţial}
prelucrează T ( listează, memorează etc.)
end
else if i = 1 then for j := 1 to dG(v0) do begin
T[i] := j; A:
generare-arbori-parţiali(i + 1); B:
end
else for j := T[i - 1] to m do
if 〈 {T[1], . . . , T[i - 1]} ∪ {j} 〉 G nu are circuite
then begin
T[i] := j; A:
generare -arbori-parţiali(i + 1); B:
end
end.

Apelul generare-arbori-parţiali(1) rezolvă problema enumerării elementelor lui TG.


Dacă G = K4 cu muchiile numerotate ca mai jos:

1
6

atunci arborii generaţi sunt următorii 16: 123, 125, 126, 134, 136, 145, 146, 156, 234,
235, 245, 246, 256, 345, 346, 356.
Pentru implementarea eficientă a testului dacă graful parţial
〈 {T[1], . . . , T[i - 1]} ∪ {j} 〉 G nu are circuite să observăm că din construcţie,
〈 {T[1], . . . , T[i - 1]} 〉 G
nu are circuite, deci componentele sale conexe sunt arbori.
Vom considera o variabilă globală rad = array[1..n] of V cu semnificaţia rad[v] =
rădăcina arborelui la care aparţine vârful v (unul din vârfurile acestui arbore).
Înaintea apelului generare-arbori-parţiali(1) se iniţializează rad[v] := v
( ∀v ∈V), ceea ce corespunde faptului că {T[1], . . . , T[i - 1]= 0.
Dacă în cursul apelurilor (recursive) se încearcă plasarea muchiei j la
38

mulţimea curentă T[1], . . . , T[i - 1], fie v= E[j,1] şi w=E[j, 2] Atunci 〈 {T[1], . . . ,
T[i - 1]} ∪ {j} 〉 G nu are circuite dacă şi numai dacă muchia vw nu are extremităţile
în aceeaşi componentă a lui
〈 {T[1], . . . , T[i - 1]} 〉 G,
adică dacă şi numai dacă rad[v] ≠ rad[w].
Vectorul rad trebuie întreţinut pentru a avea semnificaţia dorită. Acest lucru se
obţine înlocuind în procedura descrisă, instrucţiunile (vide) etichetate A şi B.
Astfel: A; se va înlocui cu secvenţa
S := ∅; x :=rad[v ];
for u∈V do if rad [u]= x then begin
S := S ∪ {u};
rad[u] := rad[w];
end

(deci) arborele cu rădăcina x se “uneşte” cu arborele cu rădăcina rad[w]; se


salvează în S vârfurile arborelui cu rădăcina x). După apelul lui trebuie refăcut
vectorul rad la valoarea de dinainte de apel, deci se va înlocui B; cu
for u∈ V do rad[u] := x.

Numărul elementelor lui TG, problemă interesantă chiar şi numai pentru


analiza algoritmului precedent, se poate determina eficient. Prezentăm în
continuare una din soluţiile posibile.
Fie G= (V, E) un multigraf cu V = {1, 2, ... ,n}. Considerăm A = (aij)n×n
matricea de adiacanţă a lui G (aij = multiplicitatea muchiei ij dacă ij ∈ E, altfel 0. Fie
D = diag(dG(1), dG(2), ... ,dG(n)).
Matricea M[G] = D - A se numeşte matricea de admitanţă a multigrafului G. Să
observăm că în M[G] suma elementelor de pe fiecare linie şi fiecare coloană este 0.

Teorema 2. (Kirchoff-Trent) Dacă G este un multigraf cu mulţimea de vârfuri 1, ... ,


n şi M[G] matricea de admitanţă, atunci

{ }
| TG | = det(M[G]ii) ∀i ∈ 1,..., n .

Observaţii: 10 M[G]ij notează minorul lui M[G] obţinut prin îndepărtarea


liniei i şi coloanei j.
20 | TG | = nn-2 (Cayley). În adevăr,
n −1 −1 L −1 
 
−1 O N M 
M[Kn] = 
 M N O −1 
 
 −1 L −1 n − 1
39

n − 1 −1 L −1
−1 O N M
det(M[Kn]11) = = nn-2
M N O −1
−1 L −1 n − 1

Observaţie. Teorema oferă un algoritm polinomial de determinare a lui |TG|.

Arbori parţiali de cost minim.

Considerăm următoarea problemă

(P1)
Date: G = (V, E) graf şi c: E -> R (c(e) - costul muchiei e).
Să se determine T*∈ TG astfel încât c(T*) = min{c(T) | T ∈ TG},
unde c(T) = ∑ c(e) .
e∈E (T )

Algoritmii cunoscuţi pentru rezolvarea problemei (P1) au la bază următoarea


ideie.
Se consideră iniţial, familia T0 = (T10, T20, . . . , Tn0) de arbori disjuncţi Ti0 =
({i},0) i = 1, n (am presupus, ca de obicei, că V = {1, 2, . . . , n}).
În pasul general k ( k = 0, 1, . . . , n-2) al algoritmului se dipune de familia
Tk = (Tk1, Tk2, . . . , Tkn-k) de n-k arbori disjuncţi astfel încât
(V(Tik))i=1,n-1 constituie o partiţie a lui V şi se constrieşte Tk+1 astfel:

- se alege Tsk unul din arborii familiei Tk.


- dintre toate muchiile lui G cu o extremitate în Tsk şi cealaltă în V - V(Tsk) se
alege una de cost minim, e* = vsvj* unde vj* ∈ V(Tj*k) j* ≠ s.
- Tk+1 = (Tk \ {Tsk, Tj*k}) ∪ T unde T este arborele obţinut din Tsk şi Tj*k la
care ad\ug\m muchia e*.
Se verific\ imediat c\ noua familie este format\ din arbori disjuncţi care
partiţionează mulţimea de vârfuri ale grafului G. Dacă alegerea umchiei e* nu este
posibilă, atunci rezultă că G nu este conex şi deci problema (P1) nu are soluţie.
Evident, familia Tn-1 construită în pasul n – 1 este formată dintr-un singur
arbore T1n-1.

Teorema 3. Dac\ G = (V, E) este un graf conex cu V= {1, 2, . . . , n}atunci arborele


construit de algoritmul descris mai sus este arbore par]ial de costminim.
Demonstra]ie. Vom ar\ta c\ ∀k ∈ {1,2, . . . ,n}) ∃T* arbore par]ial de cost
40

n−k
minim al lui G, astfel încât E(Tk)= U E(Tik)⊆ E(T*).
i =1

În particular, pantru k = n – 1, E(Tn-1) = E(Tik)⊆ E(T*) va implica T1n-1 = T*


(cei doi arbori având acela[i num\r de muchii, rezult\ c\ incluziunea are loc cu
egalitate) [i teorema este demonstrat\.
Pentru k = 0, afirma]ia este trivial adev\rat\: E(T0) = ∅ [i din conexiunea
grafului G, TG este nevid\ deci exist\ T* solu]ie a problemei P1.
Dac\ afirma]ia este adev\rat\ pentru 0 ≤ k ≤ n – 2, atunci avem E(Tk) ⊆
E(T*) (T* arbore par]ial de cost minim) [i E(Tk+1) = E(Tk) ∪ {e*}. Dac\ e*γ E(T*),
atunci, evident, E(Tk+1) ⊆ E(T*) [i deci afirma]ia are loc pentru k+1.
Presupunem, deci, c\ e*∉ E(T*). Atunci T* + {e*} con]ine exact un circuit C
ce trece prin muchia e* = vsvj*. Cum vj* ∉ V(Tsk) rezult\ c\ C va con]ine o muchie e1
≠ e* cu o extremitate în V(Tsk) [i cealalt\ în V \ V(Tsk). Din alegerea muchiei e*,
avem c(e*) ≤ c(e1) [i e1 γ E(T*) \ E(Tk).
Fie T1 = (T* + {e*}) - {e1}. T1 γ TG (este conex [i are n – 1 muchii). În plus,
c(T1) = c(T*) + c(e*) – c(e1) ≤ c(T*) deci c(T1) = c(T*) (T* este de cost minim) [i E(Tk+1)
⊆ E(T1).
Observa]ii: 10 Demonstra]ia anterioar\ r\mâne valabil\ pentru func]ii de
cost c : TG → R astfel încât ∀T ∈ TG, ∀ e ∈ E(T), ∀e’∉ E(T)

c(e’) ≤ c(e) ⇒ c((T + e’) – e) ≤ c(T)

20 În algoritmul descris nu s-a precizat modul de alegere al arborelui Tk.


Vom considera, în continuare dou\ strategii de alegere a acestui arbore.
Algoritmul lui Prim(1957) (implemetarea este datorat\ lui Dijkstra. 1961).
Arborele Tsk va fi întotdeauna arborele cu cele mai mule vârfuri dintre arborii
familiei curente. Rezult\ deci, c\ la fiecare pas k > 0, vom avea un arbore cu k + 1
vârfuri, ceilal]i n – k – 1 având câte un singur vârf. Not\m Ts = (Vs, Es) arborele
curent. Consider\m α = array [1.. n] of V [i β = array [1..n] of real tablouri cu
urm\toarea semnifica]ie:

(S) ∀j ∈ V – Vs, β[j] = c(α[j]j) = min { c(ij) | i ∈ Vs, ij∈ E}

Descrierea algoritmului.
begin
1: Vs := {s}; {s ∈ V, oarecare}.
Es := ∅;
for v ∈ V\ {s} do begin α[v] := s; β[v] := c(sv) end;
{ dac\ ij ∉ E atunci c(ij) = ∞ }
2: while Vs ≠ V do begin
determin\ j*∈ V \ Vs; β[j*] = min{β[j] | i ∈ V - Vs};
Vs := Vs ∪ {j*};
41

Es := Es ∪ {α[j*]j*};
for j ∈ V – Vs do if β[j] > c(j*j) then begin
β[j] := c(j*j);
α[j] := j*;
end
end
end.

Se observ\ c\ (S) este satisf\cut\ de ini]ializ\rile pasului 1, iar în pasul 2 se


respect\, pe de o parte, strategia general\ de alegere a muchiei de cost minime cu
exact o extremitate în Vs (alegerea lui j*) [i pe de alt\ parte se men]ine valabilitatea
condi]iei (S) pentru itera]ia urm\toare (testul asupra valorii curente a lui β[j]).
Complexitatea algoritmului este O(n-1 + n-2 + ... + 1) = O(n2), dat\ de
opera]iile din pasul 2 necesare determin\rii minimului [i actualiz\rilor tablului β.
Se poate introduce testul de conexiune a grafului, dup\ determinarea lui β[j*].
Algoritmul este recomandat în cazul grafurilor cu multe muchii, m = O(n2).
Algoritmul lui Kruskal (1956) În metoda general\ prezentat\, se va alege la
fiecare pas drept arbore Tsk unul din cei doi arbori cu proprietatea c\ sunt “uni]i”
printr-o muchie de cost minim printre toate muchiile cu extremit\]ile pe arbori
diferi]i. Aceast\ alegere, oarecum complicat\, se realizeaz\ simplu prin sortarea
muchiilor grafului nedescresc\tor în raport cu costurile [i apoi prin examinare în
mod “greedy” a listei ob]inute.
Dac\ not\m cu T = E(Tk), atunci algoritmul poate fi descris, astfel:

begin
1. Sorteaz\ E = (e1, e2, ..., em) astfel încât:
c(e1) ≤ c(e2) ≤ ... ≤ c(em ).
1.2 T := ∅; i:= 1;
2. while i ≤ m do begin
if 〈T ∪ {ei}〉G nu are circuite then
T := T ∪ {ei};
i :=i + 1;
end
end.

Evident, pasul 1 necesit\ O(m log n) opera]ii. Pentru realizarea eficient\a a


testului din pasul 2 va fi necesar s\ reprezent\m la fiecare pas k (din metoda
general\) V(T1k), V(T2k), ..., V(Tnk) [i s\ test\m dac\ muchia ei curent\ are ambele
extremit\]i în aceea[i mul]ime. Se vor folosi, pentru reprezentarea acestor mul]imi,
arbori (care nu sunt în general subarbori ai lui G).
Fiecare astfel de arbore va avea un vârf, numit r\d\cin\, care va desemna
mul]imea de vârfuri ale lui G pe care o reprezint\. Vom folosi o func]ie find(v)
42

care determin\ în ce mul]ime este vârful v, adic\ determin\ r\d\cina arborelui


care reprezint\ mul]imea de vârfuri la care apar]ine v.
Pentru realizarea reuniunilor (disjuncte) de mul]imi de vârfuri care apar în
transformarea familiilor Tk (din metoda egenral\) vom folosi o procedur\
union(u,v) cu semnifica]ia: “mul]imile de vârfuri (diferite [i disjuncte) la care
apar]in v [i w se unesc în una singur\”.
Cu aceste proceduri, pasul 2 al algoritmului se scrie:

2. while i ≤ m do begin
fie ei = vw;
if find(v) ≠ find(w) then union(u,w);
i := i + 1;
end

Complexitatea algoritmului va depinde de modul de implementare a


func]iei find [i a procedurii union.
Solu]ia Ia. Consider\m tabloul rad = array[1..n] of V cu semnifica]ia rad[v]
= r\d\cina arborelui ce reprezint\ mul]imea la care apar]ime vârful v.
Ad\ug\m pasului 1, ini]ializarea

1.3 for v ∈ V do rad[v] := v;

care corespunde familiei T0. Func]ia find are în acest caz comlpexitatea O(1) [i
este:
function find(v: V): V;
begin
find := rad[v];
end.

Procedura union necesit\ O(n) opera]ii:


procedure union(v, w: V);
var i: V;
begin
for i ∈ V do if rad[i] = rad[v] then rad[i] := rad[w];
end.

Pasul 2 al algoritmului necesit\ O(m) apeluri ale func]iei find (exact m a[a
cum l-am descris, sau O(m) dac\ se introduce un test asupra cardinalului mul]imii
T curente). ~n secven]a acestor O(m) apeluri ale func]iei find se vor intercala n – 1
apeluri ale procedurii union. Rezult\ c\ `n total pasul 2 necesit\ O(m + (n-1)O(n))
= O(n2) opera]ii. Deci complexitatea algoritmului este O(max(mlogn, n2)). Dac\
graful este plin, m = O(n2), se observ\ c\ acest algoritm este mai pu]in eficient
43

decât cel al lui Prim.


Solu]ia a IIa. Consider]m pred = array[1..n] of integer un tablou cu
interpretarea “pred[v] = vârful dinaintea lui v de pe drumul unic la v de la
r\d\cina arborelui `n care este memorat\ mul]imea la care apar]ine v.
pred[v] = 0 ⇔ v este r\d\cina acestui arbore”.
Ad\ug\m `n pasul 1, ini]ializarea
1.3 for v ∈ V do rad[v] := 0;
Cu aceast\ reprezentare a arborilor, vom modfica pasul 2 al algoritmului pentru a
realiza `n timp constant fiecare reuniune care apare:

2. while i ≤ m do begin
fie ei = vw;
x := find(v);
y := find(w);
if x ≠ y then union(u,w);
i := i + 1;
end

Deci procedura union va fi apelat\ numai pentru argumente reprezentând


r\d\cini de arbori diferi]i
procedure union(v, w: V);
begin
pred[v] = w;
end.

Evident, complexitatea procedurii union este O(1). Func]ia find este `n acest caz
mai complicat\:

function find(v: V): V;


begin
i := v;
while pred[i] > 0 do i := pred[i];
find := i;
end.

Complexitatea lui find(v) este O(h(v)) unde h(v) este lungimea drumului
din arborelee care-l con]ine pe v de la vârful v la r\d\cina acestui arbore. Dac\
graful G este K1,n-1 desenat mai jos,

3
1
44

[i lista ordonat\ a muchiilor E = {12, 13, ..., 1n}, atunci execu]ia algoritmului
provoac\ urm\torul [ir de apeluri ale procedurii union(U) [i functiei find(F):
F(1), F(2), U(1,2), F(1), F(3), U(2,3), F(1), F(4), U(3,4),..., F(1), F(n), U(n-1,n).
Apelurile F(i) (i > 1) [i U(i, i+1) i ≥ 1necesit\ `n total O(n) opera]ii. {irul de F(1)
necesit\ `ns\ O(1 + 2 + ... + n – 1) = O(n2) opera]ii.
Este deci posibil ca pasul 2 al algoritmului `n aceast\ implementare s\ fie de
complexitate Ω(n2) chiar dac\ graful este rar.
Deficien]a acestei implement\ri este datorat\ posibilit\]ii ca `n procedura
union s\ declar\m r\d\cin\ nou\ pentru cei doi arbori pe cea a celui cu mai pu]ine
vârfuri, ceea ce are ca efect posibilitatea ca h(v) s\ devin\ mare , O(n), pe parcursul
algoritmului. Aecst defect poate fi evitat dac\ la execu]ia lui union ]inem seama de
cardinalul celor dou\ mul]imi. Se poate memora cardinalul unei mul]imi `n
componenta tabloului pred corespunz\toare r\d\cinii arborelui care memoreaz\
acea mul]ime. Mai precis, consider\m ini]ializarea

1.3 for v ∈ V do rad[v] := -1;

[i modific\m procedura union astfel `ncât s\ asigur\m `ndeplinirea condi]iei


pred[v] < 0 ⇔ v este r\d\cin\ a unui arbore [i –pred[v] este cardinalul
mul]imii memorate `n el.
Procedura union are, `n acest caz tot complexitatea O(1), dar selecteaz\ drept
r\d\cin\ pe cea care corespunde cu mai multe vârfuri:

procedure union(v, w: V);


{ v [i w sunt r\d\cini }
var t: integer;
begin
t := pred[v] + pred[w];
if pred[v] > pred[w]
then begin pred[v] := w; pred[w] := t; end
else begin pred[w] := v; pred[v] := t; end
end.
45

Cu aceast\ implemetare a func]iei find [i procedurii union pe tot parcursul


algoritmului are loc:

(*) ∀v ∈ - pred[find(v)] ≥ 2h(v)

(reamintim c\ h(v) noteaz\ lungimea drumului de la v la r\d\cina find(v) a


arborelui ce memoreaz\ v).
Dup\ ini]ializarea1.3, ∀v ∈ V h(v) = 0 [i find(v) = v iar -pred[v] = 1, deci (*) are loc
cu egalitate.
Dac\, `naintea unei itera]ii din pasul 2, (*) are loc, atunci, dac\ `n acea
intera]ie nu se execut\ union, nu se modific\ pred [i deci (*) r\mâne valabil\ [i
dup\ execu]ie.
Presupunem prin urmare c\ se apeleaz\ union(x, y) [i c\ se execut\ pred[y]
:= x. Aceasta `nseamn\ c\ `naintea acestei itera]ii avem -pred[x] ≥ - pred[y]. S\
observ\m c\ singurele vârfuri v c\rora li se modific\ h(v) dup\ execu]ia itera]iei
curente sunt cele care `naintea itera]iei satisf\ceau find(v) = y, pentru care aveam -
pred[y] ≥ 2h’(v).
Dup\ execu]ia itera]iei avem h’(v) = h(v) + 1 iar find(v)’ = x, [i deci trebuie s\
verific\m c\ -pred’[y] ≥ 2h’(v). Avem –pred’[x] = –pred[x] - pred[y] ≥ 2*(–pred[y]) ≥
2*2h(v) = 2h(v)+1 = 2h’(v).
Rezult\ c\ (*) are loc pe tot parcursul algoritmului, deci ∀v ∈ V h(v) ≤ log(-
pred’[find[v]] < logn. Complexitatea pasului 2 va fi deci O(n – 1 + 2m log n) =
O(m log n) ceea ce-l face superior algoritmului lui Prim pentru grafuri rare.
Solu]ia a IIIa. Complexitatea pasului 2, cu implementarea precedent\, este
datorat\ apelurilor succesive ale lui find. Tarjan(1976) a propus ca fiecare apel al
lui find care necesit\ parcurgerea unui drum de lungime mai mare decât 1, s\
“comprime” acest drum, aducându-i vârfurile drept descenden]i imedia]i ai
r\d\cinii. Mai precis, avem

function find(v: V): V;


var i, j, k : integer;
begin
i := v;
while pred[i] > 0 do i := pred[i];
j := v;
while pred[j] > 0 do begin
k := pred[j];
pred[j] := i;
j : =k;
end
find := i;
46

end.

Dac\ A: N×N →N este func]ia lui Ackermann dat\ de: A(i, 0) = 0 ∀i ≥ 0;


A(i,1) = 2 ∀i ≥ 1; A(0, x) = 2x ∀x ≥ 0; A(i+1, x+1) = A(i, A(i+1, x)) ∀i ≥ 0 ∀x ≥ 1,
atunci considerând ∀m ≥ n > 0

α(m, n) = min { z | A(z, 4m/n) ≥ log n, z ≥ 1 }

avem: Complexitatea pasului 2, utilizând union din solu]ia a II-a [i find descris
mai sus, este O(mα(m, n)). Not\m c\ α(m, n) cre[te extrem de `ncet (pentru
valorile practice ale lui n, α(m, n) ≤ 3 [i deci se obtine ca aceast\ ultim\
implementare este practic liniar\ (`n raport cu m).

Arborescen]e

Fie G = (V, E) un digraf. Se num[te r\d\cin\ a lui G un vârf v0 ∈ V astfel


`ncât ∀v ∈ V, D v0 v ≠ ∅ (orice vârf al digrafului care este accesibil din v0 printr-un
drum `n G).
Defin]ie. Se nume[te arborescen]\ un graf orientat H = (V, E) (oricare ar fi
dou\ vârfuri , exist\ cel mult un arc cu extremit\]ile aceste dou\ vârfuri ⇔ G(H)
este graf), astfel `ncât:
(i) H are o r\d\cin\
(ii) G(H) este arbore.
Defini]ie. Un digraf G = (V, E) se nume[te quasi-tare conex dac\ ∀v, w ∈
V, ∃z∈ V astfel `ncât Dzv ≠ ∅ [i Dzw ≠ ∅.
S\ observ\m c\ dac\ G este tare conex atunci G este quasi-tare conex (se
poate lua drept z `n defini]a anterioar\, unul din cele dou\ vârfuri). Pe de alt\
parte, dac\ G este quasi-tare conex atunci G este conex.

Lema 1. G este qusi-tare conex dac\ [i numai dac\ G are o r\d\cin\.


Demonstra]ie. Dac\ G are o r\d\cin\ v0, atunci vârful z din defini]ia quasi-
tarei conexiuni poate fi luat v0.
Reciproc, dac\ G este tare-conex atunci G are o r\d\cin\. În adev\r, dac\
|V(G)| = 2 atunci unul din cele dou\ vârfuri este r\d\cin\.
Dac\, |V(G)| ≥ 3, atunci consider\m dou\ vârfuri distincte v1, v2 ∈ V(G) oa-
recare [i z ∈ V(G) astfel incit D zv1 ≠ ∅, D zv2 ≠ ∅. Fie urm\torul algoritm:

begin
1: T := {v1, v2} ∪ {z}; v0 :=z;
2: while T ≠ V do begin
fie u ∈ V – T;
47

fie t ∈ V : D tu ≠ ∅ [i D tv0 ≠ ∅; {∃t};


T := T ∪ {u}∪ {t};
v0 := t;
end
end.
Dup\ ini]ializarea din 1, are loc

(I) ∀t ∈ T, D v0t ≠ ∅

Dup\ fiecare itera]ie din pasul 2, m\car un vârf se adaug\ la T [i `n plus condi]ia
(I) r\mâne satisf\cut\. Rezult\ c\ vârful v0 construit de algoritm este r\d\cin\ a
digrafului G.
Are loc urm\toarea teorem\ de caracterizarea arboresce]elor.
Teorema 4. Fie H = (V, E) graf orientat cu n ≥ 2 vârfuri. Urm\toarele afirma]ii sunt
echivalente:
(i) H este quasi-tare conex [i G(H) nu are circuite.
(ii) H este quasi-tare conex [i are n – 1 arce.
(iii) H este arborescen]\.
(iv) ∃v0 ∈ V astfel `ncât ∀v∈ V |D v0 v | = 1.
(v) H este quasi-tare conex[i minimal cu aceast\ proprietate (∀e∈
E,
H – e nu este tare conex).
(vi) H conex [i ∃v0 ∈ V astfel `ncât dH-(v0) = 0 [i ∀v ≠ v0 dH-(v) = 1
(vii) G(H) nu are circuite [i ∃v0 ∈ V astfel `ncât dH-(v0) = 0 [i ∀v ≠ v0
-
dH (v) = 1
Demonstra]ia acestei teoreme este simpl\ ( i ⇒ ii ⇒ ... ⇒ vii ⇒ i) [i o
omitem.
Defini]ie. Fie G =(V, E) un digraf. Se nume[te arborescen]\ par]ial\ a lui G
un digraf par]ial H = (V, E’) (E’ ⊆ E) cu proprietatea c\ H este arborescen]\. Not\m

AG = { H | H arborescen]\ par]ial\ a lui G }.

Datorit\ caracteriz\rilor vi [i vii ale teoremei precedente, `n limba englez\,


o arborescen]\ par]ial\ se mai nume[te [i out-tree.

Consecin]\. AG ≠ ∅ dac\ [i numai dac\ G este quasi-tare conex.


(evident, datorit\ lui (v) din teorema 4).

O aplica]ie `n informatic\.

~n informatic\, arborescen]ele sunt numite, prin abuz de limbaj, arbori,


48

specific`ndu-se r\d\cina [i considerând implicit\ orientarea muchiilor


corespunz\tor parcurgerii drumului unic de la r\d\cin\ la fiecare v`rf. Dac\ H
este o arborescen]\ [i vw ∈ E(H) atunci w se nume[te descendent direct al lui v, iar
dH+(v) se nume[te gradul lui v `n H [i se noteaz\ dH(v). Dac\ H este o arborescen]\
astfel `nc`t dH(v) ∈ {0, 1, 2} atunci H se nume[te arbore binar. Dac\ dH(v) = 2 cei
doi descenden]i s`nt unul la st`nga [i cel\lalt la dreapta. Vârfurile cu dH(v) = 0 se
numesc terminale sau pendante (frunze), vârfurile cu dH(v) > 0 sunt interioare.

Gr\mezi.

Consider\m ∀n ∈ N* Hn = ({ 1, 2..., n}, E), unde ∀i ∈ {2, ..., n} avem arcul


i
 2 i ∈ E.
Exemplu: Pentru n=10

2 3

4 6 7
5

8 9 10

Se observ\ c\ vârfurile lui Hn sunt dispuse pe k+1 nivele 0, ..., k, unde k =


log2n, un nivel i con]inând toate vârfurile aflate la distan]a i fa]\ de r\d\cina 1.
Pe nivelul i avem 2i vârfuri, cu posibila excep]ie a ultimului nivel, care poate fi
incomplet.
Defini]ie. Tabloul A[1..n] cu elemente dintr-o mul]ime total ordonat\ (≤)
formeaz\ o gr\mad\ binar\ ("heap" `n limba englez\ ) dac\:
(H) ∀i ∈ {2,..., n} A[i ] ≥ A[ i / 2]

(interpretare: dac\ se ata[eaz\ fiec\rui vârf i al lui Hn valoarea A[i] atunci


condi]ia (H) cere ca valoarea fiec\rui vârf s\ fie ≤ decât valoarea descenden]ilor
49

s\i).

Problem\. Dat A[1..n], s\ se organizeze ca o gr\mad\.

O prim\ solu]ie este aceea de a insera un element `ntr-o gr\mad\ deja


existent\. Aplic\m acest algoritm de n - 1 ori, prima data `ntr-o gr\mad\ cu 1
element, [i continuând pân\ ce toate elementele au fost introduse.

procedure insg(var A:tablou; n:integer);


{ insereaz\ valoarea din A[n] `n gr\mada memorat\ `n A[1..n] }
var j, i: integer; v: tipul elementelor tabloului;
begin
n
j := n; i :=   ; v := A[n];
2
while i > 0 and A[i] > v do begin
A[j] := A[i]; j := i; i := [j/2];
end
A[j] :=v;
end;
Ideea procedurii insg este evident\: pe drumul de la n c\tre 1 `n Hn, se caut\
primul loc `n care s\-l plas\m pe v, conform cerin]ei (H). Construirea gr\mezii este
atunci,
for i := 2 to n do insg(A,i);

Complexitatea construc]iei: `n cazul cel mai nefavorabil, oricare ar fi i, toate cele 2i


noduri de pe nivelul i se plimb\ pân\ `n r\d\cin\ (pentru a-[i g\si locul), deci
log n  log n 
Tn ≤ ∑
i =1
i 2i < log n ∑2
i =1
i
= O(n log n) .

Exist\ o strategie general\ `n astfel de probleme, care permite o construc]ie mai


bun\ : echilibrarea. Dac\ `n procedura insg interpret\m c\ se combin\ o gr\mad\
cu n - 1 elemente cu o gr\mad\ cu 1 element, atunci urm\toarea procedur\ face
echilibrarea.

procedure combg(i, n: integer);


{ gr\mada cu r\d\cina A[2i] [i gr\mada cu r\d\cina A[2i+1] se combin\ cu
valoarea A[i] pentru a forma o gr\mad\ cu r\d\cina A[i]; tabloul A este
variabil\ global\ }
var k, j: integer; v: ...
begin
k := i; j := 2i; v := A[i];
while j ≤ n do begin
50

if (j < n) and (A[j] > A[j + 1]) then j:=j+1;


if v ≥ A[ij] then begin
A[k] := A[j]; k := j; j:=2j;
end
else j := n + 1;
end;
A[k] :=v;
end;
Se observ\ c\ `n cel mai r\u caz, se va executa o plimbare pân\ la ultimul nivel.
Cu aceast\ procedur\, construc]ia gr\mezii se face astfel
procedure balg(var A:tablou; n:integer);
var i:integer;
begin
n
for i :=   downto 1 do combg(i, n);
2
end;
Complexitatea construc]iei gr\mezii cu balg. Fie 2k −1 ≤ n ≤ 2 k ; (k − 1 = log n );
nivelele lui Hn sunt 0, 1,..., k-1, [i pentru fiecare nod de pe nivelul i se fac cel mult k
– i coborâri. Rezult\ :
k −2 k k
Tn ≤ ∑ 2i (k − i ) = ∑ 2 k − j j ≤ n∑ j / 2 j < 2n = O(n)
i =0 j =2 j =2

O coad\ cu prioritate este o structur\ de date, care permite extragerea


minimului [i introducerea unui nou element, `n mod eficient. O gr\mad\ poate fi
folosit\ ca o coad\ cu prioritate astfel:
i) Inser]ia `n O(log n) opera]ii cu insg;
ii) extragerea minimului `n O(log n) opera]ii, astfel: se extrage elementul
din r\d\cin\; plas\m `n r\d\cin\ elementul de pe ultimul [i folosim
combg(1, n-1) pentru a reface gr\mada .
Not\m c\ `n acest exemplu, utilizarea arborescen]ei Hn s-a f\cut pentru ilustrarea
comport\rii algoritmilor. Heapsort, sortarea cu ajutorul gr\mezilor (Floyd) este
evident\:

procedure heapsort(A,n);
{ sorteaz\ descresc\tor A[1..n] }
begin
balg(A,n);
for i = n downto 2 do begin
t := A[i]; A[i] := A[1]; A[1] := t;
combg(A,i-1);
end
51

end.

S-ar putea să vă placă și