Structura laboratorului se gaseste in acest link.
La fel ca la arbori de acoperire, presupunem că fiecare muchie are un cost de parcurgere.
Într-un graf, orice drum este definit de o succesiune de muchii (cu proprietatea că, pentru oricare două muchii consecutive din succesiune, nodul destinaţie/de sosire al primei muchii este acelaşi cu nodul sursa/de plecare al celei de-a doua muchii).
Costul unui drum va fi definit ca suma costurilor muchiilor ce compun acel drum.
Fie un nod sursă(S) şi un nod destinaţie(D). Pot exista mai multe drumuri de la S la D(drumuri care au S = primul nod, D = ultimul nod), iar drumul de cost minim de la S la D va fi cel mai ieftin(cu costul cel mai mic) dintre acestea. (OBS - pot exista mai multe drumuri de cost minim de la S la D).
Următorii algoritmi caută drumurile de cost minim de la un singur nod(sursă) la toate celelalte noduri. Rezultatul acestor algoritmi este un arbore cu drumuri de cost minim, unde:
Algoritmi:
Un algoritm pentru determinarea celei mai scurte cai de la un varf la oricare alt varf e algoritmul lui Dijkstra. (OBS - acesta nu functioneaza pentru grafuri cu circuite negative(in cazul in care exista circuite de cost negativ, costum minim pentru orice varf care apartine circuitului, ar putea fi considerat -INF, iar algoritmul nu detecteaza aceste circuite)
Algoritm:
atribuim un posibil cost(o estimare a distanţei) pentru fiecare nod. (iniţial, S are costul 0, toate celelalte noduri au costul infinit);
Pasii:
1. Declarăm două mulţimi: mulţimea nodurilor neexplorate(MN), iniţial MN conţine toate nodurile; mulţimea nodurilor explorate(ME) ce compun arborele, iniţial ME = vidă; 2. Atribuim fiecărui nod o estimare iniţială a costului: 0 pentru nodul sursă(S); infinit pentru toate celelalte; 3. Cât timp există noduri în MN 1. Alegem, din MN(nodurile neexplorate), nodul cu cel mai mic cost estimat îl numim C(nodul curent) 2. pentru fiecare din vecinii lui C care se află în MN 3. calculăm noua estimare de cost = cost(drumul S-C) + cost(muchia (C,V)); 4. comparăm noua estimare cu vechiul cost(drumul S-V): dacă noul cost e mai bun 1. actualizăm cost(drumul S-V) = noul cost; 2. actualizăm parinte(V) = C; (pentru păstrarea muchiei folosite) altfel păstrăm vechiul cost 5. Marcăm nodul C ca explorat: îl eliminăm din MN şi îl adăugăm în ME. (Nu va mai fi verificat)
Algoritmul Bellman-Ford determina drumurile de cost minim de la un varf sursa la fiecare dintre celalalte varfuri, identificand eventualele circuite de cost negativ.
Pasii sunt similari ca cei ai algoritmului Dijkstra:
1. Atribuim fiecărui nod o estimare iniţială a costului: 0 pentru nodul sursă(S); infinit pentru toate celelalte; 2. Executăm de N-1 ori: 1. Pentru fiecare pereche (u, v) a.i. există muchie de la u la v 1. calculăm noua estimare de cost = cost(drumul S-u) + cost(muchia (u,v)); 2. comparăm noua estimare cu vechiul cost(drumul S-v): dacă noul cost e mai bun 1. actualizăm cost(drumul S-v) = noul cost; 2. actualizăm parinte(v) = u; (pentru păstrarea muchiei folosite) altfel păstrăm vechiul cost 3. Dupa executare, pentru identificarea circuitelor de cost negativ, se verifica fiecare pereche (u,v) a.i exista muchie de la u la v cu conditia ca noul cost sa fie mai bun. In cazul in care exista, se va returna valoarea 0 si 1, in caz contrar.
Algoritmul Floyd-Warshall, caută cel mai scurt drum de la orice nod sursă(S) la fiecare nod destinaţie(D).
Rezultatul algoritmului este o matrice N x N(unde N = |V|, numărul de noduri), iar valorea din matrice de la poziţia [i][j] va fi costul minim pentru drumul i-j. Fie această matrice numită dist.
1. Declarăm matricele: dist, matrice N x N şi o iniţializăm dist[i][j] = infinit, pentru orice i şi j next, matrice N x N în care vom salva prima muchie din drumul i-j de cost minim //next este necesar doar în cazul în care ne interesează muchiile folosite //pasul k = 0 2. Pentru fiecare nod v 1. dist[v][v] = 0; 3. Pentru fiecare pereche (u,v) a.i. există muchie de la u la v 1. dist[u][v] = costMuchie(u,v); 2. next[u][v] = v; //pentru urmărirea muchiilor ce compun drumul //am terminat pasul k = 0 4. Pentru fiecare pas k (de la 1 la N) 1. Pentru fiecare nod i (de la 1 la N) 1. Pentru fiecare nod j (de la 1 la N) 1. calculăm costul nou = dist[i][k] + dist[k][j]; 2. comparăm costul nou cu costul vechi = dist[i][j] dacă e mai bun costul nou: 1. dist[i][j] = costul nou; 2. next[i][j] = next[i][k]; //pentru urmărirea muchiilor altfel păstrăm costul vechi
Pentru simplitate, algoritmul numerotează nodurile de la 1 la N şi foloseşte următoarea construcţie: costMinim(i,j,k) = cel mai ieftin drum care pleaca din i, ajunge in j, iar nodurile parcurse intermediar fac parte din {1,2,3…k} (primele k noduri).
OBS - Pentru obţinerea nodurilor ce formează drumul de cost minim de la u la v, putem folosi următoarea secvenţă:
funcţie afişareDrum(u, v) 1. dacă u == v 1. print(v); STOP 2. print(u); 3. afişareDrum(next[u][v], v);