This is an old revision of the document!
Adobe is a global technology leader with a mission to change the world through personalized digital experiences. For over four decades, Adobe has transformed how individuals, teams, businesses, and enterprises create, manage, and deliver content across every surface and channel.
With AI at the core, tools like Adobe Firefly and AI-powered assistants make creativity faster, smarter, and more personalized—while keeping it safe and responsible. In Adobe Experience Cloud, AI powers real-time personalization, predictive insights, and automated customer journeys, helping brands deliver exceptional experiences at scale. At Adobe, creativity meets productivity, and AI is the catalyst for transformation.
În laboratorul anterior am introdus contextul pentru Shortest-paths problem și Single-source shortest-paths problem. În laboratorul 10 vom continua cu All-pairs shortest-paths problem.
Vă rugăm să parcugeți Shortest-paths problem pentru a vă familiariza cu contextul, problema și notațiile folosite.
Concepte necesare:
În acest laborator vom studia all-pairs shortest-paths problem. Pentru această problemă, vom prezenta 2 algoritmi:
Vom prezenta fiecare algoritm, îl vom analiza, iar la final vom vedea când îl vom folosi pe fiecare.
Puteți consulta capitolul All-Pairs Shortest Paths din Introduction to Algorithms [0] pentru mai multe detalii despre acești algoritmi.
Algoritmul Roy-Floyd (Roy-Floyd / Floyd–Warshall algorithm) rezolvă shortest-paths problem în grafuri G = (V, E) care sunt dense.
// apply Roy-Floyd's algorithm for all-pairs shortest-paths problem // // nodes = list of all nodes from G // adj[node] = the adjacency list of node // example: adj[node] = {..., neigh, ...} => edge (node, neigh) of cost w[node][neigh] // // // returns: d, p // d = distance matrix // p = parent matrix // Roy-Floyd(G=(nodes, adj)) { // STEP 1: initialize results // d[i][j] = minimum distance from i to j // p[i][j] = parent of node j, on shortest path from i to j for (i in nodes) { for (j in nodes) { d[i][j] = w[i][j]; // edge cost (or infinity if missing) p[i][j] = (w[i][j] != infinity ? i : null); // parent (or null if missing) } } // STEP 2: For each intermediar node k, // try to update shortest path from i to j. for (k in nodes) { for (i in nodes) { for (j in nodes) { // Is (i -> ... -> k) reunion with (k -> ... -> j) shorter than (i -> ... -> j)? if (d[i][k] + d[k][j] < d[i][j]) { d[i][j] = d[i][k] + d[k][j]; p[i][j] = p[k][j]; } } } } return d, p; } // Usage example: d, p = Roy-Floyd(G=(nodes, adj)); // 1. Use distances from d // 2. Rebuild path from node to source using parents (p) RebuildPath(source, destination, p);
Algoritmul lui Johnson (Johnson’s algorithm) rezolvă shortest-paths problem în grafuri G = (V, E) care sunt rare.
Ideea de la care pornește acest algoritm este de a rula cel mai rapid algorithm pentru shortest-paths single source, adică algoritmul lui Dijkstra, pentru fiecare sursă (nod) din graf. Dacă toate costurile sunt pozitive, putem face direct acest lucru. Dacă însă există costuri negative, nu putem aplica Dijkstra pe acest graf. Algoritmul lui Johnson face o preprocesare (în ComputeH) și calculează un graf echivalent, în care toate costurile sunt pozitive. Pe acest graf se poate aplica Dijkstra și să se afle toate distanțele. Ulterior se face translatarea inversă și se obțin distanțele în graful inițial.
Observație: Dacă se știe că toate costurile din graf sunt pozitive (nenegative), algoritmul lui Johnson se poate înlocui cu rularea directă a algoritmului Dijkstra pentru toate nodurile din graf.
// apply Johnson's algorithm for all-pairs shortest-paths problem // // nodes = list of all nodes from G // adj[node] = the adjacency list of node // example: adj[node] = {..., neigh, ...} => edge (node, neigh) of cost w[node][neigh] // // returns: has_cycle, d, p // has_cycle = negative cycle detection flag (true if found) // d = distance matrix (defined only if has_cycle == false) // p = parent matrix (defined only if has_cycle == false) // Johnson(G=(nodes, adj)) { // STEP 1: Compute adjustment distances h (using Bellmand-Ford). has_cycle, h = ComputeH(G); if (has_cycle) { return true, null, null; } // STEP 2: Update all costs in G to obtain all costs nonnegative. foreach ((u, v) in edges) { if (w[u][v] != infinity) { w[u][v] = w[u][v] + (h[u] - h[v]); } } // STEP 3: Now all costs are nonnegative, so we can apply Dijsktra. // Start Dijkstra for each source u, saving just distances. foreach (u in nodes) { d_dijkstra, p_dijkstra = Dijkstra(u, G); // STEP 4: Compute distance (u, v) on initial graph. foreach (v in nodes) { d[u][v] = d_dijkstra[v] + (h[v] - h[u]); p[u][v] = p_dijkstra[v]; } } return false, d, p; // no negative cycles detected } ComputeH(G=(nodes, adj)){ // STEP 0: Create a new **temporary** graph // * add a new node source = new node; new_nodes = nodes + { source }; new_adj = adj; // * add a new edge (source, node) with cost 0 for all existing nodes for (node in nodes) { new_adj[source].push_back(node); w[source][node] = 0; } // STEP 1: Run Bellman-Ford on the new graph. Save just flag and distances. has_cycle, h, _ = Bellmann-Ford(source, new_G=(new_nodes, new_adj))) if (has_cycle) { return true, null; // negative cycle detected } return false, d; } // Usage example: has_cycle, d, p = Johnson(source, G=(nodes, adj)); if (has_cycle) { print "Has Cycle!" STOP. } else { // 1. Use distances from d // (e.g. d[node] = distance from source to node) // // 3. Rebuild path from node to source using parents (p) RebuildPath(source, destination, p); }
În această secțiune exemplificăm grafic cum rulează algoritmul lui Johnson pe un graf dat.
Scheletul de laborator se găsește pe pagina pa-lab::skel/lab10.
Înainte de a rezolva exercițiile, asigurați-vă că ați citit și înțeles toate precizările din secțiunea Precizari laboratoare 07-12.
Prin citirea acestor precizări vă asigurați că:
Enunț: O companie are N sucursale și mai multe drumuri bidirecționale, fiecare având o anumită distanță. O configurație a sucursalelor care rămân deschise este considerată validă dacă distanța minimă dintre oricare două sucursale deschise nu depășește o limită dată. Sarcina este să găsești numărul total de configurații valide (inclusiv configurația în care toate sucursalele sunt închise).
Date de intrare: Un număr întreg N reprezentând numărul de sucursale, un număr întreg maxDistance reprezentând distanța maximă permisă și o matrice roads, unde fiecare element este un triplet [u, v, weight] ce reprezintă un drum bidirecțional și lungimea acestuia.
Date de ieșire: Un singur număr întreg reprezentând numărul total de configurații valide de sucursale.
Problema se poate testa la: \ LeetCode - Number of Possible Sets of Closing Branches
Enunț: Se dau două șiruri de caractere, source și target, de aceeași lungime, formate exclusiv din litere mici ale alfabetului englez, și trei vectori: original, changed și cost. O literă din original se poate transforma în litera corespunzătoare din changed plătind costul asociat din cost. Se cere găsirea costului minim total pentru a transforma șirul source în șirul target, știind că operațiile de transformare pot fi aplicate în lanț de oricâte ori.
Date de intrare: Șirurile de caractere source și target, împreună cu vectorii de transformare original, changed și cost.
Date de ieșire: Un singur număr întreg reprezentând costul minim pentru transformarea întregului șir, sau -1 dacă transformarea este imposibilă.
Problema se poate testa la: LeetCode - Minimum Cost to Convert String I
Enunț: Se dă o matrice de dimensiune N × N care reprezintă potențialele distanțe minime dintre oricare două noduri dintr-un graf orientat (adică rezultatul aplicării algoritmului Roy-Floyd). Se cere să se verifice dacă această matrice este validă și, în caz afirmativ, să se determine numărul minim de muchii pe care ar trebui să le aibă graful inițial pentru a genera exact aceste distanțe.
Date de intrare: Numărul de teste T. Pentru fiecare test, se dă numărul de noduri N, urmat de o matrice de dimensiune N × N ce reprezintă distanțele.
Date de ieșire: Pentru fiecare test, se va afișa pe o linie separată “NU” dacă nu se poate construi un astfel de graf. Dacă este posibil, se va afișa “DA”, urmat de un spațiu și de numărul minim de muchii ale grafului inițial.
Problema se poate testa la: Infoarena - rfinv
[0] Chapters Single-Source Shortest Paths / All-Pairs Shortest Paths, “Introduction to Algorithms”, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein.