Considerăm un graf neorientat ponderat (cu costuri) conex G
. Se numește arbore parțial un graf parțial al lui G
care este arbore. Se numește arbore parțial de cost minim un arbore parțial pentru care suma costurilor muchiilor este minimă.
Dacă graful nu este conex, vorbim despre o pădure parțială de cost minim.
Algoritmul lui Kruskal permite determinarea unui arbore parțial de cost minim (APM) într-un graf ponderat cu N
noduri.
Pentru a determina APM-ul se pleacă de la o pădure formată din N
subarbori. Fiecare nod al grafului reprezintă inițial un subarbore. Aceștia vor fi reuniți succesiv prin muchii, până când se obține un singur arbore (dacă graful este conex) sau până când acest lucru nu mai este posibil (dacă graful nu este conex).
Algoritmul este:
Principala dificultate în algoritmul descris mai sus este stabilirea faptului că extremitățile muchiei curente fac sau nu parte din același subarbore. În acest scop vom stabili pentru fiecare subarbore un nod special, numit reprezentant al (sub)arborelui și pentru fiecare nod din graf vom memora reprezentantul său (de fapt al subarborelui din care face parte) într-un tablou unidimensional.
Pentru a stabili dacă două noduri fac sau nu parte din același subarbore vom verifica dacă ele au același reprezentant. Pentru a reuni doi subarbori vom înlocui pentru toate nodurile din subarborele B cu reprezentantul subarborelui A.
Înlocuirile descrise mai sus sunt simple dar lente. Pentru o implementare mai eficientă a algoritmului se poate folosi conceptul de Padure de mulțimi disjuncte, descris în acest articol.
Vom determina, folosind Algoritmul lui Kruskal, arborele parțial de cost minim pentru graful de mai jos.
Muchiile se vor analiza în ordinea crescătoare a costului.
Se adaugă muchia (7,8)
de cost 1
Se adaugă muchia (3,9)
de cost 2
Se adaugă muchia (6,7)
de cost 2
Se adaugă muchia (1,2)
de cost 4
Se adaugă muchia (3,6)
de cost 1
Se ignoră muchia (7,9)
de cost 6
Se adaugă muchia (3,4)
de cost 7
Se ignoră muchia (8,9)
de cost 7
Se adaugă muchia (1,8)
de cost 8
Se ignoră muchia (2,3)
de cost 8
Se adaugă muchia (4,5)
de cost 9
Se ignoră muchia (5,6)
de cost 10
Se ignoră muchia (2,8)
de cost 11
Se ignoră muchia (4,6)
de cost 14
Vom determina, folosind Algoritmul lui Kruskal, arborele parțial de cost minim pentru graful de mai jos:
Muchiile se vor analiza în ordinea următoare:
1. | Se adaugă muchia (7,8) de cost 1 |
|
2. | Se adaugă muchia (3,9) de cost 2 |
|
3. | Se adaugă muchia (6,7) de cost 2 |
|
4. | Se adaugă muchia (1,2) de cost 4 |
|
5. | Se adaugă muchia (3,6) de cost 1 |
|
6. | Se ignoră muchia (7,9) de cost 6 |
|
7. | Se adaugă muchia (3,4) de cost 7 |
|
8. | Se ignoră muchia (8,9) de cost 7 |
|
9. | Se adaugă muchia (1,8) de cost 8 |
|
10. | Se ignoră muchia (2,3) de cost 8 |
|
11. | Se adaugă muchia (4,5) de cost 9 |
|
12. | Se ignoră muchia (5,6) de cost 10 |
|
13. | Se ignoră muchia (2,8) de cost 11 |
|
14. | Se ignoră muchia (4,6) de cost 14 |
Următoarea secvență determină costul total al APM-ului, folosind algoritmul lui Kruskal. Presupunem că graful are cel mult 100
de noduri.
struct muchie{ int i,j,cost; }; int n , m , t[101]; muchie x[5000]; int main() { cin >> n >> m; for(int i = 0 ; i < m ; ++i) cin >> x[i].i >> x[i].j >> x[i].cost; //sortare tablou x[] după campul cost // ... de completat //initializare reprezentanti for(int i =1 ; i <= n ; ++i) t[i] = i; //determinare APM int S = 0; for(int i = 0 ; i < m ; i ++) if(t[x[i].i] != t[x[i].j]) // extremitatile fac parte din subrabori diferiti { S += x[i].cost; //reunim subarborii int ai = t[x[i].i], aj = t[x[i].j]; for(int j =1 ; j <= n ; ++j) if(t[j] == aj) t[j] = ai; } cout << S << "\n"; return 0; }
Considerăm un graf neorientat ponderat (cu costuri) conex G
. Se numește arbore parțial un graf parțial al lui G
care este arbore. Se numește arbore parțial de cost minim un arbore parțial pentru care suma costurilor muchiilor este minimă.
Dacă graful nu este conex, vorbim despre o pădure parțială de cost minim.
Algoritmul lui Prim permite determinarea unui arbore parțial de cost minim (APM) într-un graf ponderat cu N
noduri.
Determinarea APM-ului se face astfel:
Observație: arborele parțial de cost minim al unui graf neorientat nu este unic, însă toate APM-urile vor avea același cost.
Mai jos este descris modul în care se aleg nodurile care se adaugă în arbore pentru un graf ponderat cu N=9
noduri:
Nodul ințial este 1
. Costul curent al APM este 0
Se adaugă nodul 2
. Muchia folosită este (1,2)
. Costul curent al APM este 40
Se adaugă nodul 3
. Muchia folosită este (2,3)
. Costul curent al APM este 120
Se adaugă nodul 9
. Muchia folosită este (3,9)
. Costul curent al APM este 140
Se adaugă nodul 6
. Muchia folosită este (3,6)
. Costul curent al APM este 180
Se adaugă nodul 7
. Muchia folosită este (6,7)
. Costul curent al APM este 200
Se adaugă nodul 8
. Muchia folosită este (7,8)
. Costul curent al APM este 210
Se adaugă nodul 4
. Muchia folosită este (3,4)
. Costul curent al APM este 280
Se adaugă nodul 5
. Muchia folosită este (4,5)
. Costul curent al APM este 370
Algoritmul poate fi implementat în mai multe moduri, cu complexități diferite.
N-1
ori):
Față de varianta anterioară se evită căutarea propriu zisă a nodului din arbore, căutându-se efectiv numai nodul din afara acestuia. Pentru aceasta se păstrează un șir d[]
cu următoarea semnificație: pentru un nod k
încă neadăugat în arbore, d[k]
reprezintă costul minim al unei muchii având o extremitate k
și o extremitate în arbore; dacă o asemenea muchie nu există d[k] = INFINIT
.
Dacă determinarea succesivă a nodurilor din afara arborelui se face prin parcurgerea șirului d[]
, complexitatea devine O(N
2
)
.
Se poate evita parcurgerea șirului d[]
prin memorarea nodurilor din arbore într-o structură de date de tip heap, în vârful heap-ului fiind nodul k
pentru care d[k]
are valoare minimă. În acest fel complexitatea algoritmului devine O(N logN)
.