Algoritmul lui Dijkstra este un algoritm grafic inventat de savantul olandez Edsger Dijkstra în 1959 . Găsește cele mai scurte căi de la unul dintre vârfurile graficului la toate celelalte. Algoritmul funcționează numai pentru grafice fără muchii cu greutate negativă . Algoritmul este utilizat pe scară largă în programare, de exemplu, este utilizat de protocoalele de rutare OSPF și IS-IS .
Opțiunea 1. Având în vedere o rețea de drumuri care leagă orașele din regiunea Moscovei. Unele drumuri sunt cu sens unic. Găsiți cele mai scurte căi de la orașul A la fiecare oraș din regiune (dacă vă puteți deplasa doar pe drumuri).
Opțiunea 2. Există o serie de zboruri între orașele lumii, costul fiind cunoscut pentru fiecare. Costul unui zbor de la A la B poate să nu fie egal cu costul unui zbor de la B la A. Găsiți ruta cu cost minim (eventual cu transferuri) de la Copenhaga la Barnaul .
Dat un grafic ponderat direcționat [1] fără arce de greutate negativă [2] . Găsiți cele mai scurte căi de la un vârf al graficului la toate celelalte vârfuri ale acestui grafic.
Fiecărui vârf de la V i se atribuie o etichetă — distanța minimă cunoscută de la acest vârf la un .
Algoritmul funcționează pas cu pas - la fiecare pas „vizitează” un vârf și încearcă să reducă etichetele.
Algoritmul se termină când toate nodurile au fost vizitate.
Inițializare .
Eticheta vârfului a însuși se presupune a fi 0, etichetele celorlalte vârfuri sunt setate la infinit.
Acest lucru reflectă faptul că distanțele de la a la alte vârfuri nu sunt încă cunoscute.
Toate vârfurile graficului sunt marcate ca nevizitate.
Pasul algoritmului .
Dacă toate nodurile au fost vizitate, algoritmul se termină.
În caz contrar, din nodurile care nu au fost încă vizitate, este selectat vârful u cu eticheta minimă.
Luăm în considerare toate rutele posibile în care u este penultimul punct. Vârfurile la care duc muchiile de la u se numesc vecine acestui vârf. Pentru fiecare vecin al lui u , cu excepția celor marcate ca vizitate, luați în considerare o nouă lungime de cale egală cu suma valorilor etichetei curente u și lungimea muchiei care leagă u cu acest vecin.
Dacă valoarea lungimii primite este mai mică decât valoarea etichetei vecinului, înlocuiți valoarea etichetei cu valoarea lungimii obținute. Luând în considerare toți vecinii, marchem vârful u ca vizitat și repetăm pasul algoritmului .
Luați în considerare execuția algoritmului pe exemplul graficului prezentat în figură.
Să fie necesar să se găsească cele mai scurte distanțe de la primul vârf la toate celelalte.
Cercurile indică vârfurile, liniile indică căile dintre ele (marginile graficului).
Numărul de vârfuri este indicat în cercuri, greutatea lor este indicată deasupra marginilor - lungimea căii.
Lângă fiecare vârf, este marcată o etichetă roșie - lungimea celei mai scurte căi către acest vârf de la vârful 1.
Primul pas .
Vârful 1 are eticheta minimă. Vârfurile 2, 3 și 6 sunt vecine.
Primul vecin al vârfului 1, la rândul său, este vârful 2, deoarece lungimea căii către acesta este minimă.
Lungimea căii către acesta prin vârful 1 este egală cu suma valorii etichetei vârfului 1 și lungimea muchiei care merge de la 1 la 2, adică 0 + 7 = 7.
Aceasta este mai mică decât eticheta curentă a vârfului 2, infinit, deci noua etichetă a celui de-al doilea vârf este 7.
Efectuăm o operație similară cu alți doi vecini ai primului vârf - al 3-lea și al 6-lea.
Toți vecinii nodului 1 sunt verificați.
Distanța minimă actuală până la vârful 1 este considerată finală și nu este supusă revizuirii.
Tăiați-o din grafic pentru a marca că acest vârf a fost vizitat.
Al doilea pas .
Din nou găsim „cel mai apropiat” dintre vârfurile nevizitate. Acesta este vârful 2 etichetat 7.
Din nou încercăm să reducem etichetele vecinilor vârfului selectat, încercând să trecem prin ele prin al 2-lea vârf. Vecinii vârfului 2 sunt vârfurile 1, 3 și 4.
Primul (în ordine) vecin al vârfului 2 este vârful 1. Dar acesta a fost deja vizitat, așa că nu facem nimic cu primul vârf.
Următorul vecin este vârful 3, deoarece are eticheta minimă.
Dacă mergeți la el prin 2, atunci lungimea unei astfel de căi va fi egală cu 17 (7 + 10 = 17). Dar eticheta curentă a celui de-al treilea vârf este 9, care este mai mică de 17, deci eticheta nu se schimbă.
Un alt vecin al vârfului 2 este vârful 4.
Dacă mergeți la el prin al 2-lea, atunci lungimea unei astfel de căi va fi egală cu suma celei mai scurte distanțe până la al 2-lea vârf și a distanței dintre vârfurile 2 și 4, adică 22 (7 + 15 = 22) .
Deoarece 22< , setăm eticheta vârfului 4 la 22.
Toți vecinii vârfului 2 au fost vizualizați, înghețăm distanța până la acesta și îl marchem ca vizitat.
Al treilea pas .
Repetăm pasul algoritmului selectând vârful 3. După „procesarea” acestuia, obținem următoarele rezultate:
Următorii pași .
Repetăm pasul algoritmului pentru vârfurile rămase. Acestea vor fi vârfurile 6, 4 și, respectiv, 5.
Finalizarea executiei algoritmului .
Algoritmul se termină când toate nodurile au fost vizitate.
Rezultatul algoritmului este vizibil în ultima figură: cea mai scurtă cale de la vârful 1 la 2 este 7, la 3 este 9, la 4 este 20, la 5 este 20, la 6 este 11.
Dacă la un moment dat toate vârfurile nevizitate sunt marcate cu infinit, atunci aceasta înseamnă că aceste vârfuri nu pot fi atinse (adică, graficul nu este conectat ). Apoi algoritmul poate fi finalizat înainte de program.
Mai jos este codul pentru implementarea algoritmului în limbajul de programare Java . Această opțiune de implementare nu este cea mai bună, dar arată clar posibila implementare a algoritmului:
clasa Dijkstra { dublu [] dist = dublu nou [ GV () ] ; Edge [] pred = margine nouă [ GV () ] ; public Dijkstra ( WeightedDigraph G , int s ) { boolean [] marcat = boolean nou [ GV () ] ; pentru ( int v = 0 ; v < GV ( ); v ++ ) dist [ v ] = Dublu . POSITIVE_INFINITY ; MinPQplus < Double , Integer > pq ; pq = nou MinPQplus < Double , Integer > (); \\ Coada prioritară dist [ s ] = 0,0 ; pq . pune ( dist [ s ] , s ); în timp ce ( ! pq . este gol ()) { intv = pq . _ delmin (); dacă ( marcat [ v ] ) continuă ; marcat ( v ) = adevărat ; pentru ( Muchia e ( v )) { int w = e . la (); dacă ( dist [ w ]> dist [ v ] + e . greutate ()) { dist [ w ] = dist [ v ] + e . greutate (); pred [ w ] = e ; pq . insert ( dist [ w ] , w ); } } } } }Atribui
Pentru toate altele decât , atribuim .
la revedere . Fie un vârf cu minim
Pentru toți cei care
dacă atunci
Schimbare
Schimbare
În cea mai simplă implementare, o matrice de numere poate fi folosită pentru a stoca numerele d [ i ], iar o matrice de variabile booleene poate fi folosită pentru a stoca apartenența unui element în mulțimea U.
La începutul algoritmului, se presupune că distanța pentru vârful inițial este zero și toate celelalte distanțe sunt umplute cu un număr pozitiv mare (mai mare decât calea maximă posibilă din grafic ). Tabloul flags este umplut cu zerouri. Apoi începe bucla principală.
La fiecare pas al buclei, căutăm un vârf cu o distanță minimă și un steag egal cu zero. Apoi setăm steagul la 1 și verificăm toate vârfurile adiacente acestuia . Dacă în ele (în ) distanța este mai mare decât suma distanței până la vârful curent și lungimea muchiei, atunci o reducem. Bucla se termină când steagurile tuturor nodurilor devin egale cu 1 sau când toate nodurile cu steag sunt 0 . Cel din urmă caz este posibil dacă și numai dacă graficul G este deconectat.
Fie lungimea celei mai scurte căi de la vârf la vârf . Să demonstrăm prin inducție că în momentul vizitei oricărui vârf , egalitatea este valabilă .
Baza. Vârful este vizitat mai întâi . În acest moment .
Etapa. Să presupunem că am ales un vârf de vizitat . Să demonstrăm că în acest moment . Pentru început, observăm că pentru orice vârf este întotdeauna valabil (algoritmul nu poate găsi o cale mai scurtă decât cea mai scurtă dintre toate cele existente). Să fie calea cea mai scurtă de la la . Vârful este pornit și nu este vizitat. Prin urmare, setul de vârfuri nevizitate nu este gol. Fie primul vârf nevizitat pe , și fie cel care îl precede (deci vizitat). Deoarece calea este cea mai scurtă, porțiunea care duce de la până la este și cea mai scurtă, deci .
Prin ipoteza de inducție, în momentul vizitei vârfului , , prin urmare, vârful a primit apoi o etichetă nu mai mare decât . Prin urmare, . Dacă , atunci se dovedește etapa de inducție. În caz contrar, deoarece vârful este selectat în prezent și nu , eticheta este minimă printre cele nevizitate, adică . Combinând acest lucru cu , avem , ceea ce urma să fie demonstrat.
Deoarece algoritmul se termină atunci când toate nodurile au fost vizitate, în acel moment pentru toate nodurile.
Complexitatea algoritmului lui Dijkstra depinde de modul în care este găsit vârful v , de modul în care este stocat setul de vârfuri nevizitate și de cum sunt actualizate etichetele. Notați cu n numărul de vârfuri și cu m numărul de muchii din graficul G .
constantele ascunse în estimările de cost asimptotice sunt mari, iar utilizarea grămezilor Fibonacci este rareori adecvată: grămezile binare obișnuite ( d-ary ) sunt mai eficiente în practică.
Alternativele la acestea sunt grămada groase, grămada subțire și grămada Brodal , care au aceleași estimări asimptotice, dar constante mai mici [4] .
Algoritmi de căutare grafică | ||
---|---|---|
Metode neinformate | ||
Metode informate | ||
Comenzi rapide | ||
Arborele de întindere minim | ||
Alte |