Sunteți pe pagina 1din 74

Teoria grafurilor

Definitie grafuri
Grafurile sunt tupluri (V, E), unde V = multime de noduri si E = multime de muchii. Prin grafuri putem
descrie modele precum o retea de strazi dintr-un oras. In acest context putem defini:

● O muchie reprezinta o strada


● Un nod reprezinta o intersectie

Putem descrie strazi cu sens unic? Putem descrie “fundaturi”? Putem descrie mai multe orase simultan?
Putem avea mai multe strazi intre aceleasi doua intersectii? Putem avea o strada ce are la ambele capete
aceeasi intersectie? -> Da
O retea de strazi descrisa printr-un graf
Exemplu de graf
De regula, nodurile se deseneaza in forma de cerc,
iar in interiorul lor se scrie numele nodului. In
majoritatea cazurilor, numele nodului este numarul
sau de ordine. In cazul din dreapta avem 6 noduri.

Muchiile in acest caz sunt segmentele trasate intre


exact doua noduri. In cazul din dreapta avem 7
muchii.
Mai multe exemple de grafuri
Nomenclatura
Un graf neorientat este un graf in care muchiile nu au “sens”. Cu alte
cuvinte, drumurile se pot forma in ambele sensuri peste orice muchie.

Un graf orientat este un graf in care muchiile au “sens”. Cu alte cuvinte,


drumurile se pot forma doar intr-un singur sens pe fiecare muchie.

Unele denumiri difera depinzand de tipul grafului: neorientat sau orientat.


Nomenclatura
Doua noduri sunt vecine / adiacente daca exista o muchie intre ele. (ex: 5 si
6 sunt vecine)

O muchie este incidenta intr-un nod daca un capat al muchiei este chiar
nodul. (muchia dintre 1 si 2 este incidenta in nodul 1)

Gradul unui nod este numarul de muchii incidente in acesta. (gradul nodului
1 este 2).

Doua muchii sunt adiacente daca au un capat (nod) comun . (muchia dintre
11 si 12 este adiacenta cu cea dintre 12 si 13)
Nomenclatura
Un lant este o secventa de noduri adiacente . (nodurile 1, 3, 6, 5, 7 formeaza
un lant). Lungimea lantului este dimensiunea secventei de noduri.
(lungimea este de 5)

O componenta conexa este un subset de noduri maximal in care exista lant


intre oricare doua noduri cuprinse. (nodurile 11, 12, 13 formeaza o
componenta conexa)

Un nod este izolat este un nod cu grad 0. (ex: nodul 14)

Un graf planar este un graf ce se poate desena pe hartie fara ca doua muchii
sa se suprapuna. (graful din imagine este planar)

Un nod A este accesibil din nodul B, daca exista lant intre A si B. (nodul 7
este accesibil din nodul 2)
Nomenclatura
Un subgraf este un alt graf a carui multime de noduri este o submultime de
noduri a grafului original. Multimea de muchii este submultimea de muchii
ce au ambele noduri incidente in multimea de noduri rezultata. (graful V =
[1, 3, 4, 6], E = [(1, 3), (3, 4), (4, 6)] este un subgraf)

Un graf partial este un alt graf cu acelasi set de noduri, insa doar cu o
submultime de muchii.

Un graf este conex daca este format dintr-o singura componenta conexa.
Atentie! Daca in probleme nu se specifica conexitatea grafului, vom
presupune ca graful poate avea mai multe componente conexe.

Un nod terminal/frunza este un nod cu gradul 1 (nodul 9 este un nod


frunza).
Exemplu de graf cu muchii multiple/bucla
Intr-un graf putem avea si:

● Muchii multiple, adica multimi de muchii ce au


aceeasi pereche de noduri incidente (desenate cu
rosu)
● Muchii bucla (loop), adica muchii ce au nodurile
incidente identice (desenate in albastru

Atentie! Daca in probleme nu se specifica explicit ca


testele nu contin grafuri cu muchii multiple sau bucla,
trebuie sa avem grija caci acestea trebuie tratate de
regula special.
Reprezentarea grafurilor
Pentru a reprezenta un graf in cod, putem sa ne folosim de una dintre urmatoarele cele mai populare trei
metode:

● Matrice de adiacenta: o matrice booleana in care M[i][j] este true daca exista muchie intre nodurile i
si j, sau false in caz contrar. In cazul grafurilor neorientate, M[i][j] == M[j][i].
● Vectori/liste de adiacenta: fiecare nod va avea asociat un vector ce contine identificatorii nodurilor
adiacente cu acesta. In cazul grafurilor neorientate, daca A se afla in lista de adiacenta a lui B, atunci
si B se afla in lista de adiacenta a lui A.
● Vector/lista de muchii: un vector de pair-uri. Fiecare pair descrie o muchie, adica contine
identificatorii nodurilor incidente. In cazul grafurilor neorientate, daca muchia (A, B) se afla in lista
de muchii, atunci si (B, A) trebuie sa se afle in lista de muchii.
Matrice de adiacenta
Matrice de adiacenta
Scenariu Complexiate

Sunt doua noduri adiacente? O(1)

Cata memorie consuma? O(|V| * |V|)

Care este gradul unui nod, este frunza, este izolat? O(|V|)

Inserarea/stergerea unei muchii. O(|1|)


Vectori de adiacenta
● 1: 4
● 2: 4
● 3: 4
● 4: 1, 2, 3

● 1: 2, 4
● 2: 1, 3
● 3: 2, 4
● 4: 1, 3

● 1: 2, 3, 4
● 2: 1, 3, 4
● 3: 1, 2, 4
● 4: 1, 2, 3
Vectori de adiacenta
Scenariu Complexiate

Sunt doua noduri adiacente? O(|V|) - se poate si mai bine

Cata memorie consuma? O(|E|)

Care este gradul unui nod, este frunza, este izolat? O(1)

Inserarea/ștergerea unei muchii. O(|1|) - inserare, O(|V|) - stergere


Vector de muchii
● [(1, 4), (4, 1), (2, 4), (4, 2), (3, 4), (4, 3)]

● [(1, 2), (2, 1), (1, 4), (4, 1), (4, 3), (3, 4), (3,
2), (2, 3)]

● [(1, 2), (2, 1), (1, 3), (3, 1), (1, 4), (4, 1), (2,
3), (3, 2), (2, 4), (4, 2), (3, 4), (4, 3)]
Vector de muchii
Scenariu Complexiate

Sunt doua noduri adiacente? O(|E|)

Cata memorie consuma? O(|E|)

Care este gradul unui nod, este frunza, este izolat? O(|E|)

Inserarea/stergerea unei muchii. O(|1|) - inserare, O(|E|) - stergere


Probleme
Antrenament Usoare Medii

Adiacenta Adiacenta1
ListaVecini Matad
Grade
Izolate
GradMax
Subgraf
Gengraf
Grad partial
Documentatie

● http://webserv.lgrcat.ro/2010-2011/Catedre/Informatica/11/graf1.pdf
● https://www.pbinfo.ro/articole/810/grafuri-neorientate
Grafuri orientate
In cadrul grafurilor orientate, fiecare muchie are un
sens. In fapt, in grafurile orientate nu avem
denumirea de muchie, ci de arc.

Prin urmare, daca exista un drum intre doua noduri


A si B, nu este obligatoriu sa avem si drumul intre B
si A.

Majoritatea cuvintelor specifice grafurilor


neorientate se regasesc si la cele orientate.
Nomenclatura
Un graf neorientat este un graf in care muchiile nu au “sens”. Cu alte
cuvinte, drumurile se pot forma in ambele sensuri peste orice muchie.

Un graf orientat este un graf in care muchiile au “sens”. Cu alte cuvinte,


drumurile se pot forma doar intr-un singur sens pe fiecare muchie.

Unele denumiri difera depinzand de tipul grafului: neorientat sau orientat.


Nomenclatura
Un nod este vecine / adiacente cu altul in cazul in care exista o muchie de la
al doilea la primul. (ex: 11 este vecin cu 5, dar nu si invers)

O muchie este incidenta intr-un nod in cazul in care capatul muchiei este
nodul respectiv. (muchia dintre 5 si 11 este incidenta in 11, dar nu si in 5)

Gradul intern al unui nod este numarul de muchii ce intra in acesta. (gradul
intern al nodului 8 este 2).

Gradul extern al unui nod este numarul de muchii ce iesa din acesta. (gradul
extern al nodului 8 este 1).
Nomenclatura
Un drum este o secventa de noduri adiacente . (nodurile A, B, C, F, C
formeaza un drum). Lungimea drumului este dimensiunea secventei de
noduri. (lungimea este de 5)

O componenta tare conexa este un subset de noduri maximal in care exista


drum intre oricare doua noduri cuprinse. (nodurile G, H, I, J, K, L formeaza o
componenta conexa)

Un nod A este accesibil din nodul B, daca exista drum intre A si B. (nodul L
este accesibil din nodul A)
Nomenclatura
Un subgraf este un alt graf a carui multime de noduri este o submultime de
noduri a grafului original. Multimea de muchii este submultimea de muchii
ce au ambele noduri incidente in multimea de noduri rezultata. (graful V =
[1, 3, 4, 6], E = [(1, 3), (3, 4), (4, 6)] este un subgraf)

Un graf partial este un alt graf cu acelasi set de noduri, insa doar cu o
submultime de muchii.
Matrice de adiacenta

(0, 1, 1, 0)
(0, 0, 0, 0)
(0, 1, 0, 1)
(0, 0, 1, 0)
Vectori de adiacenta

● 1: 2, 3
● 2:
● 3: 2, 4
● 4: 3
Vector de arce

[(1, 2), (1, 3), (3, 2), (3, 4), (4, 3)]
Parcurgerea grafurilor
In principal, exista doua metode de parcurgere populare a grafurilor in complexitate O(|E|):

● DFS (Depth First Search) - se bazeaza pe o stiva pentru parcurge graful


● BFS (Breadth First Search) - se bazeaza pe o coada pentru a parcurge graful

Atentie! Ambele metode sunt folosite pentru a parcurge o singura componenta conexa. In cazul in care
avem mai multe componente, trebuie sa aplicam un algoritm (DFS sau BFS) pentru fiecare componenta in
parte.
DFS
DFS urmeaza urmatorii pasi:

1. Alegem un nod de start (sa presupunem 0)


2. Daca exista un vecin nevizitat, vom merge in
acesta si vom relua pasul 2
3. Daca exista nu exista vecin nevizitati, ne vom
intoarce in nodul din care am venit si vom
relua pasul 2
BFS
BFS urmeaza urmatorii pasi:

1. Alegem un nod de start (sa presupunem 0) si


il punem intr-o coada
2. Adaugam toti vecinii acestuia in coada si ii
marcam drept vizitati
3. Eliminam nodul curent din coada si
continuam pasul 2 cu urmatorul nod din
coada.
Probleme
Antrenament Usoare Medii

BFS Conex
DFS Gegik
Grade2
GradIntNul
Mere
Bazine
Probleme bonus
Usoare Medii

Party
Ring Road
Grafuri orientate - Recapitulare
In cadrul grafurilor orientate, fiecare muchie are un
sens. In fapt, in grafurile orientate nu avem
denumirea de muchie, ci de arc.

Prin urmare, daca exista un drum intre doua noduri


A si B, nu este obligatoriu sa avem si drumul intre B
si A.

Majoritatea cuvintelor specifice grafurilor


neorientate se regasesc si la cele orientate.
Componente tare conexe
O componenta tare conexa este un subset de
noduri maximal in care exista drum intre oricare
doua noduri cuprinse. (nodurile G, H, I, J, K, L
formeaza o componenta conexa)
Algoritmul lui Kosaraju
Un algoritm fundamental pentru detectia
componentelor tare conexe este algoritmul lui
Kosaraju. Complexitatea este O(|V| + |E|), ceea ce
inseamna ca este un algoritm optim pentru
rezolvarea prolemei. Un alt algorim ce rezolva
problema gasirii componentelor tare conexe este
Algoritmul lui Trajan (ce functioneaza mai repede in
practica desi are aceeasi complexitate teoretica).
Algoritmul lui Kosaraju - Pasul 1
Pasul 1 consta intr-o traversare DFS a grafului. In
timpul traversarii, vom memora intr-o stiva
nodurile “finale” (din care nu am mai reusit sa
continuam DFS-ul) in ordinea in care le-am intalnit.
Nodul de start poate fi ales aleatoriu. De asemenea,
e posibil sa nu reusim sa parcurgem tot graful
dintr-un singur DFS. Trebuie sa pornim DFS-uri din
noduri nevizitate pana cand toate nodurile vor fi
traversate.

Stiva: B, C, D, E, A

Vizitate: A, B, E, D, C
Algoritmul lui Kosaraju - Pasul 2
Pasul 2 reprezinta construirea grafului invers. Cu
alte cuvinte, trebuie sa generam un graf cu acelasi
set de noduri, insa in care fiecare muchie din graful
original va fi inversate in graful secund. (daca avem
muchie de la i la j in graful original, atunci vom
avem muchie de la j la i in graful auxiliar).

Acest graf are numele de graf transpus al grafului


original.
Algoritmul lui Kosaraju - Pasul 3
Pasul 3 presupune a parcurge DFS graful generat.
Ordinea alegerii nodurilor de start va fi data de
stiva construita la pasul 1. Daca am vizitat un nod
din stiva, il eliminam. Componentele individuale
parcurse de DFS vor reprezenta componente tare
conexe in graful initial.

Stiva: B, C, D, E, A

Vizitate: A, C, D, E, B

Componente: (A, C, D, E), (B)


Algoritmul lui Kosaraju - Corectitudine
Intrebarea corectitudinii vine abia in pasul 3. De ce alegerea in ordine a punctelor de start ne genereaza
componente tare conexe in graful original.

Din primul pas observam ca, avand un nod i in stiva, toate nodurile accesibile din i sunt sub acesta in stiva.

Stiva: B, C, D, E, A
Algoritmul lui Kosaraju - Corectitudine
Din prima observatie, deducem ca nodurile accesibile din varful stivei sunt toate sub acesta in stiva.

In pasul 2, constructia grafului transpus ne ajuta sa parcurgem graful in ordine inversa. Cu ale cuvinte, daca
traversam muchia i, j in graful transpuns, atunci i este accesbil din j in graful original.
Algoritmul lui Kosaraju - Corectitudine
In final, in ultimul pas vom parcurge componenta tare conexa a nodului de start ales. Din faptul ca il alegem
pe baza stivei create la pasul 1, inseamna ca toate nodurile accesibile de acesta ramase se afla sub acesta in
stiva - deci nevizitate inca. Din parcurgerea DFS de la pasul 3, demonstram si accesbilitatea in sens invers.
Daca exista lant de la X la Y si de la Y la X, inseamna ca acestea trebuie sa se afle in aceeasi componenta tare
conexa.
Probleme - CTC
Antrenament Usoare Medii

Ctck CtcMax Nuclee


Arce_inutile
Grafuri cu costuri (ponderat)
Un graf cu costuri este format dintr-un graf suport
(orientat sau neorientat) si o functie de cost, care
asociaza fiecarei muchii un numar (numit costul
muchiei)

In practica, aceasta reprezentare are menirea de a


sugera distanta dintre doua noduri adiacente.
Atentie la muchii multiple sau muchii bucla in
ideea grafurilor cu cost!
Grafuri cu costuri
Pentru a reprezenta un graf cu cost vom avea
urmatoarele modificari in structurile obisnuite:

● Matricea de adiacenta va stoca la M[i][j],


costul muchiei de la i la j.
● Vectorii de adiacenta vor stoca pairuri
continand nodul vecin si costul muchiei.
● Vectorul de muchii vor stoca un struct
continand capetele muchiei si costul ei.
Grafuri cu costuri - Matrice de adiacenta
Matricea de adiacenta in cadrul grafurilor cu cost,
nu vor mai stoca 0 sau 1 reprezentand existenta
unei muchii. Acestea vor stoca direct costul
muchiei, ori o valoare neutra (0, -1, infinit)
reprezentand inexistenta unei muchii. Cum putem
descrie muchii multiple sau muchii bucla?

infinit 3 infinit 7 8

3 infinit 1 4 infinit

infinit 1 infinit 2 infinit

7 4 2 infinit 3

8 infinit infinit 3 infinit


Grafuri cu costuri - Vectori de adiacenta

Vectori de adiacenta in cadrul grafurilor cu cost, nu


vor mai stoca doar etichetele nodurilor. In schimb,
vectorii vor fi formati din pariruri intre eticheta
nodului vecin si costul muchiei intre nodul curent si
nodul vecin aferent. Cum putem descrie muchii
multiple sau muchii bucla?

(1, 3) (3, 7) (4, 8)

(0, 3) (3, 4) (2, 1)

(1, 1) (3, 2)

(0, 7) (1, 4) (2, 2) (4, 3)

(0, 8) (3, 3)
Grafuri cu costuri - Vector de muchii
Vectorul de muchi in cadrul grafurilor cu cost, nu va
mai stoca pairuri continand capete de muchii. In
schimb acesta va fi format din structuri ce contin
informatii despre capetele muchiei si costul
acesteia. Cum putem descrie muchii multiple sau
muchii bucla?
Grafuri cu costuri
Distanta minima intre doua noduri din graf este
cea mai mica valoare a unui lant/drum intre cele
doua noduri. Prin valoare intelegem suma
costurilor de pe muchiile alese.

In cadrul grafurilor orientate, este important sa


specificam ce directie are drumul (de la i la j ori de
la j la i). Fiind graf orientat, distanta minima de la i la
j poate fi diferita de cea de la j la i.

Daca avem un ciclu de cost negativ, atunci distanta


minima nu are sens!
Algoritmul Roy-Floyd-Warshall
Algoritmul Roy-Floyd-Warshall este un algoritm de
detectie a tuturor distantelor minime intr-un graf.

Complexitatea algoritmului este O(|V|3) si se


bazeaza pe o reprezentare a grafului de tip matrice
de adiacenta.
Algoritmul Roy-Floyd-Warshall - idee
Vom defini functia matematica distMin(i, j, k) ce
reprezinta distanta minima de la i la j folosind doar
noduri cu indici cel mult k (exceptand capetele).
Algoritmul Roy-Floyd-Warshall - idee
Asadar putem defini functia distMin(i, j, k) folosind
urmatoarele expresii

● distMin(i, j, k-1) - este acelasi drum ca cel


creat la pasul anterior (ignorand nodul k)
● distMin(i, k, k-1) + distMin(k, j, k-1) - folosim un
drum nou, unde nodul k este un nod
intermediar

Formula finala presupune alegerea minimului


dintre cele doua expresii de mai sus.
Algoritmul Roy-Floyd-Warshall - bonus
Pana acum am definit o functie distMin(i, j, k), pe
care daca o apelam astfel: distMin(start, finish, |V|),
putem, obtine distanta minima intre start, finish
intr-o complexitate O(N3), daca folosim memoizare
in procesul recursiv.

Exista algoritmi mai performanti pentru acest


scenariu (distanta minima intre doua noduri)!!!
Algoritmul Roy-Floyd-Warshall se foloseste de
observatiile de mai devreme pentru a determina
toate drumurile minime in graf.
Algoritmul Roy-Floyd-Warshall
Algoritmul acesta are mai degraba o a abordare
iterativa decat recursiva. Mai mult de atat, filosofia
implementarii trebuie sa fie una bottom-up.

Vom rezolva problema pentru valorile mici ale lui k,


iar pe urma, folosindu-ne de aceste valori
intermediare, putem determina solutii pentru
valori mai mare ale lui k.

Conform formulei de mai devreme, calcului lui


distMin(i, j, k) depinde integral de valori ale lui
distMin cu al treilea parametru k-1.
Algoritmul Roy-Floyd-Warshall - initializare
Initial avem matricea de adiacenta, unde vom
completa cu infinit celulele aferente nodurilor
neadiacente. Elemenetele de pe diagonala
principala trebuie insa sa ramana 0.

Putem privi deja aceasta matrice ca o matrice de


distante. M[i][j] reprezinta distanta minima dintre i
si j. Evident, la inceput doar M[i][j] (i si j adiacente
sau identice) are o valoare diferita de infinit.

Dupa executarea Roy-Floyd-Warshall, matricea va


fi populata cu drumuri minime in graf, deci la sfarsit
M[i][j] = distanta minima intre i si j.
Algoritmul Roy-Floyd-Warshall
Pe urma, pentru fiecare k posibil in ordine
crescatoare (pentru exemplu de la 0 la 4), vom
recalcula matricea. Asta inseamna ca vom calcula
toate distMin(i, j, k) posibile, tinand seama ca
distMin(i, j, k-1) este defapt M[i][j].

Distantele noi calculate (adica distMin(i, j, k)) vor


fi stocate inapoi in M[i][j].

Din pricina faptului ca actualizarea valorilor la


pasul k a lui M[i][j] nu ne afecteaza calcului unui
ipotetic M[x][y], atunci nu este obligatoriu sa facem
copii la M, ori valorile sa fie salvate in alta matrice!
Algoritmul Roy-Floyd-Warshall - finalizare
In urma rularii algorimului in O(N3), vom avea in
matricea M toate distantele minime in graf.

Daca aveam nevoie de graful original (costurile


originale), ar fi trebuit sa salvam intr-o matrice
separata ori in alta structura (vectori de adiacenta)
graful initial.
Algoritmul Roy-Floyd-Warshall - discutie
Ce se intampla cand graful are mai multe
componente conexe?

Ce se intampla cand avem muchii multiple sau


muchii bucla?

Ce se schimba in cadrul grafurilor orientate? Ce se


poate intampla cand graful are mai multe
componente tare conexe?

Cand ar trebui sa folosim acest algoritm, stiind ca


exista algoritmi mai buni pentru detectia distantei
minime intre doua noduri?

Ce schimbari trebuie sa facem pentru a puteam


lucra si cu costuri negative?
Probleme - Algoritmul RFW
Antrenament Usoare Medii

Roy-Floyd Graf
RF
Arbori
Un arbore este un graf conex si aciclic (fara cicluri).

Un ciclu in graf este un lant/drum elementar de


lungime cel putin 3, ce incepe si se termina cu
acelasi nod.

Intre oricare doua noduri din arbore exista un


singur lant elementar.

Numarul de noduri este intotdeauna egal cu


numarul de muchii plus unu: |V| = |E| + 1

Un graf in care fiecare componenta conexa


reprezinta un arbore se numeste padure.
Arbori liberi vs arbori cu radacina
Un arbore cu radacina este un arbore in care a fost ales un nod
drept radacina, iar prin urmare, unele noduri capata anumite
proprietati datorita pozitiei lor relative fata de radacina. Nodurile
cu un singur vecin au denumirea de frunze. Nodurile ce nu sunt
frunze si nici radacina se numesc noduri interne.

Un arbore fara o radacina aleasa se numeste liber.

In cadrul unui arbore cu radacina vom avea urmatorii termeni:

● Tata/Ascendent direct: nodul vecin prin care trece lantul


dintre nodul curent si radacina. Radacina nu are tata.
● Fiu/Descendent direct: nodurile vecine cu exceptia tatalui.
Frunzele nu au fii.
Arbori cu radacina
● Subarbore: multimea de noduri X alese astfel incat lantul
de la X la radacina trece prin nodul curent.
● Ascendent/Stramos: un nod de pe lantul dintre nodul
curent si radacina.
● Descendent: un nod ce apartine subarborelui nodului
curent
● Nivel/Adancime: lungimea lantului ce leaga radacina de
nodul curent. Radacina se afla pe nivelul 0.
● Frati: nodurile ce au nodul tata comun.
● Inaltimea: cel mai lung lant elementar ce pleaca din
radacina. Inaltimea este egala cu cel mai mare nivel din
arbore.
● Diametru: cel mai lung lant elementar din arbore.
Reprezentarea arborilor
Ca orice alt graf, un arbore se poate reprezenta
prin structurile clasice: matrice de adiacenta,
vector de adiacenta, vector de muchii. Evindent,
matricea de adiacenta este foarte ineficienta in
cadrul reprezentarii arborilor din cauza memoriei
utilizate O(|V|^2) in comparatie cu O(|E|) = O(|V|).

Pe langa cele 3 metode mentionate mai dispunem


de urmatoarele metode in cadrul arborilor cu
radacina:

● Vectori de fii
● Vector de tati
Reprezentarea arborilor - vectori de fii
In cadrul vectorilor de fii, fiecare nod va stoca in
propriul lui vector multimea de fii ai sai. Prin
urmare, aceasta metoda este foarte asemanatoare
cu vectorii de adiacenta.

Aceasta metoda de stocare este utila doar in cadrul


parcurgerilor descendente, deoarece putem sa
efectuam doar miscari de “coborare”.
Vector de fii
Scenariu Complexiate

Sunt doua noduri adiacente? O(|V|)

Cata memorie consuma? O(|E|)

Cine este tatal nodului curent? O(|E|)

Cati fii are nodul curent? O(|1|)


Reprezentarea arborilor - vector de tati
In cadrul vectorului de tati, fiecare nod are asociat
un tata. In fapt, vectorul de tati este un vector
caracteristic, unde T[i] reprezinta tatal nodului i.
Daca i este radacina, atunci T[i] are o valoare
neutra (-1/0/infinit).

Aceasta metoda de stocare este utila doar in cadrul


parcurgerilor ascendente, deoarece putem sa
efectuam doar miscari de “urcare”.
Vector de tati
Scenariu Complexiate

Sunt doua noduri adiacente? O(|1|)

Cata memorie consuma? O(|V|)

Cine este tatal nodului curent? O(|1|)

Cati fii are nodul curent? O(|V|)


Algoritmul de determinare a diametrului
Pas 1: Se executa o parcurgere DFS din radacina arborelui. Daca
arborele nu este agatat, vom alege o radacina in mod aleatoriu. In
cadrul DFS-ului vom cauta cel mai indepartat nod de radacina.

Pas 2: Se executa un al doilea DFS din nodul aflat la pasul 1. Acest


DFS va avea scopul de a afla cel mai indepartat nod de nodul de
start. Cu alte cuvinte, vom folosi acelasi DFS ca la pasul 1.

Capetele diametrului sunt: nodul determinat dupa pasul 1 si


nodul determinat dupa pasul 2. Lantul dintre cele doua noduri
reprezinta diametrul. Lungimea diametrului poate fi aflata in
urma executarii pasului 2.
Probleme
Antrenament Usoare Medii

Arbore Frunze
AfisareFii Nivele
Darb Tata
Subarbore Inaltime
kNivel
NrFii
DetDrum
DetDrum1
DetDrum2
Distanta minima in graf intre 2 noduri
Distanta minima in graf intre doua noduri se refera la lungimea celui mai scurt lant/drum intre cele doua
noduri. Asadar, distanta minima are sens doar in grafuri ponderate. In cele neponderate, putem
presupune ca ponderea fiecarei muchii este 1, ori aplicam un algoritm eficient precum BFS.
Algoritmul lui Dijkstra
Algoritmul lui Dijkstra se bazeaza pe determinarea minimului de la un nod la restul nodurilor. In fapt,
algoritmul lui Dijkstra este un exemplu de programare dinamica, in care dp[i] = distanta minima de la
nodul de start la nodul i. Evident, putem deduce relatia de recurenta:

dp[i] = min(dp[vecin] + cost), pentru fiecare muchie dintre i si vecin ce are costul cost

Problema care apare este cea a ordinii in care construim dp. Nu putem construi dp in ordine liniara,
deoarece putem avea unele variabile in formula necalculate inca.
Ordinea construcției dp
Un anumit dp este calculat corect doar in cazul in care dpul vecinilor este deja calculat corect. Ce se
intampla daca nu calculam bine dp-ul din prima? Putem face mai multe parcurgeri liniare si sa actualizam
dp-ul pana cand acesta se stabilizeaza. Aceasta tehnica apartine O(n^3) - complet ineficient.

Insa putem face o observatie cheie: minimul din vector este deja stabilizat - oricate iteratii am mai face el
ramane la fel. Cu alte cuvinte, putem la fiecare pas sa consideram nodul cu distanta minima deja calculat,
si vom actualiza DOAR vecinii acestuia. Aceasta observatie aduce complexitatea la O(n^2).
Ultima optimizare
Observam ca dorim la fiecare pas, minimul dintr-o multime si eventual sa actualizam alte minime din
aceasta. Pentru aceasta sarcina, vom avea nevoie de o structura de date potrivita: anume stl::set.

Pentru a gasi minimul, vom interoga inceputul setului. (Begin)

Pentru a actualiza minimele, le scoatem pe cele vechi din set si le introducem pe cele noi (find, erase,
insert)

Aceasta optimizare duce la o complexitate de O(m + nlogn)


Detalii de implementare

La fiecare pas, vom considera doar noul minim creat, celelalte minime le marcam vizitate

Initial, dp-urile vor fi initializate cu infinit, mai putin dp de start care va fi pus pe 0

Ne oprim din iterare dupa n pasi - adica atunci cand setul va fi gol

Nu trebuie sa uitam sa scoatem valorile vechi din set - altfel vom aloca f multa memorie

Algoritmul merge pe grafuri neorientate si orientate, cu self-loop si muchie multipla.

Algoritmul nu merge pe grafuri cu cicluri negative - vom avea minime tot mai mici
Probleme
Antrenament Usoare Medii

Dijkstra Firma Ubuntzei


Parc Graph
Festivaluri Joc
Vacanta