Dijkstrin algoritam — najkraći putevi u grafu

Dijkstrin algoritam pronalazi najkraće rastojanje od jednog početnog čvora do svih ostalih čvorova u grafu. Radi ispravno samo ako su sve težine grana nenegativne.

Ovo je jedan od najvažnijih algoritama u grafovima i spada u greedy algoritme. Na svakom koraku bira čvor sa najmanjom trenutno poznatom udaljenošću i "zapečati" njegov rezultat.

Kada koristiti Dijkstru?

Algoritam se koristi kada:

  • graf ima težine (dužine, vreme, cena...)
  • sve težine su nenegativne
  • želimo najkraći put od polaznog do svih ostalih čvorova

Primeri:

  • navigacija (GPS)
  • video igre
  • mreže i rutiranje
  • lavirinti

Ideja algoritma

Za svaki čvor čuvamo udaljenost od starta. Početno stanje:

  • start = 0
  • ostali = ∞

Na svakom koraku:

  1. biramo najbliži neobrađen čvor
  2. radimo relaksaciju suseda
  3. ponavljamo

Relaksacija:


ako je dist[u] + w(u,v) < dist[v]:
    ažuriraj dist[v]
    

Implementacija (C++) — priority_queue


// uključuje sve standardne biblioteke
#include <bits/stdc++.h>
using namespace std;

const int INF = 1e9;

// graf: lista suseda (čvor, težina)
vector<pair<int,int>> graf[100];

// niz udaljenosti
vector<int> d;

void dijkstra(int start, int n){
    // inicijalizacija
    d.assign(n+1, INF);
    d[start] = 0;

    // min-heap (udaljenost, čvor)
    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
    pq.push({0, start});

    while(!pq.empty()){
        auto [dist, v] = pq.top();
        pq.pop();

        // ako je zastareo unos - preskoči
        if(dist > d[v]) continue;

        // prolazak kroz susede
        for(auto [sused, w] : graf[v]){
            if(d[v] + w < d[sused]){
                d[sused] = d[v] + w;
                pq.push({d[sused], sused});
            }
        }
    }
}
    

Korišćenje


int main(){
    int n = 5;

    // dodavanje grana
    graf[1].push_back({2, 7});
    graf[1].push_back({3, 9});
    graf[2].push_back({4, 10});
    graf[3].push_back({4, 2});
    graf[4].push_back({5, 1});

    dijkstra(1, n);

    for(int i = 1; i <= n; i++)
        cout << "distanca do " << i << " = " << d[i] << endl;
}
    

Rekonstrukcija najkraćeg puta


vector<int> parent;

void dijkstra(int start, int n){
    d.assign(n+1, INF);
    parent.assign(n+1, -1);
    d[start] = 0;

    priority_queue<pair<int,int>, vector<pair<int,int>>, greater<pair<int,int>>> pq;
    pq.push({0, start});

    while(!pq.empty()){
        auto [dist, v] = pq.top();
        pq.pop();

        if(dist > d[v]) continue;

        for(auto [sused, w] : graf[v]){
            if(d[v] + w < d[sused]){
                d[sused] = d[v] + w;
                parent[sused] = v; // čuvamo prethodnika
                pq.push({d[sused], sused});
            }
        }
    }
}

// vraća put od starta do cilja
vector<int> rekonstruiši_put(int cilj){
    vector<int> put;
    for(int v = cilj; v != -1; v = parent[v])
        put.push_back(v);

    reverse(put.begin(), put.end());
    return put;
}
    

Greške koje treba izbegavati

  • Negativne težine → koristi Bellman-Ford
  • Ne prekidati prerano (osim ako tražiš jedan cilj uz optimizaciju)
  • Obavezna provera: if(dist > d[v]) continue;

Složenost algoritma

Struktura Složenost
Heap O((V + E) log V)
Matrica O(V²)

Dijkstrin algoritam — najkraći putevi u grafu


Dijkstrin algoritam pronalazi najkraće rastojanje od jednog početnog čvora do svih ostalih čvorova u grafu. Radi ispravno samo ako su sve težine grana nenegativne.

Ovo je jedan od najvažnijih algoritama u grafovima i spada u greedy algoritme. Na svakom koraku bira čvor sa najmanjom trenutno poznatom udaljenošću i "zapečati" njegov rezultat.



Kada koristiti Dijkstru?


Algoritam koristi se kada:

  • graf ima težine (dužine, vreme, cena...)
  • sve težine su nenegativne
  • želimo najkraći put od polaznog do svih ostalih čvorova

Primeri:

  • navigacija na mapi (Google Maps, GPS)
  • najbrži način da pređemo nivo u video igri
  • optimizacija mreža i protoka podataka
  • najkraća ruta kroz maze/lavirint


Ideja algoritma


Za svaki čvor čuvamo udaljenost od starta. Na početku, udaljenost startnog čvora je 0, a svih ostalih je beskonačno (∞).

Na svakom koraku:

  1. izaberemo neobrađen čvor sa najmanjom udaljenošću (greedy korak)
  2. pokušamo da relaksiramo (poboljšamo) susedne čvorove
  3. ponavljamo dok ne obradimo sve čvorove

Relaksacija:


ako je dist[u] + w(u,v) < dist[v]:
    onda ažuriraj dist[v]


Implementacija (C++) — verzija sa priority_queue


Najbolja i najčešća implementacija koristi prioritetni red (min-heap).


#include 
using namespace std;

const int INF = 1e9;

vector> graf[100]; 
// graf[x] = lista parova (sused, težina)

vector d; // udaljenosti

void dijkstra(int start, int n){
    d.assign(n+1, INF);
    d[start] = 0;

    priority_queue, vector>, greater>> pq;
    pq.push({0, start}); // (udaljenost, čvor)

    while(!pq.empty()){
        auto [dist, v] = pq.top();
        pq.pop();

        if(dist > d[v]) continue; // preskačemo ako nije aktuelno

        for(auto [sused, w] : graf[v]){
            if(d[v] + w < d[sused]){
                d[sused] = d[v] + w;
                pq.push({d[sused], sused});
            }
        }
    }
}

Korišćenje:


int main(){
    int n = 5; // broj čvorova

    // dodavanje grana (u, v, tezina)
    graf[1].push_back({2, 7});
    graf[1].push_back({3, 9});
    graf[2].push_back({4, 10});
    graf[3].push_back({4, 2});
    graf[4].push_back({5, 1});

    dijkstra(1, n);

    for(int i=1; i<=n; i++)
        cout << "distanca do " << i << " = " << d[i] << endl;
}


Rekonstrukcija najkraćeg puta


Da bismo znali konkretan put, čuvamo prethodnika (parent) svakog čvora.


// dodati uz postojeći kod

vector parent;

void dijkstra(int start, int n){
    d.assign(n+1, INF);
    parent.assign(n+1, -1);
    d[start] = 0;

    priority_queue, vector>, greater>> pq;
    pq.push({0, start});

    while(!pq.empty()){
        auto [dist, v] = pq.top();
        pq.pop();

        if(dist > d[v]) continue;

        for(auto [sused, w] : graf[v]){
            if(d[v] + w < d[sused]){
                d[sused] = d[v] + w;
                parent[sused] = v;      // pamti putanju
                pq.push({d[sused], sused});
            }
        }
    }
}

// funkcija za vraćanje puta
vector rekonstruiši_put(int cilj){
    vector put;
    for(int v = cilj; v != -1; v = parent[v])
        put.push_back(v);
    reverse(put.begin(), put.end());
    return put;
}


// primer poziva
auto put = rekonstruiši_put(5);
for(int x : put) cout << x << " ";


Vizuelni primer


Graf:

1 →2 (7), 1→3 (9), 3→4 (2), 4→5 (1), 2→4 (10)

Izvor: 1

Najkraći put 1 → 3 → 4 → 5 = 12



Greške koje treba izbegavati


  • Ne sme biti **negativnih težina** (onda se koristi Bellman-Ford).
  • Ne sme se završiti kada se pusti cilj — Dijkstra ide dok se svi ne obrade.
  • Ne porediti nova rastojanja bez provere `if(dist > d[v]) continue;`.


Složenost algoritma


Struktura Složenost
Prioritetni red (heap) O((V + E) log V)
Matrična reprezentacija O(V²)


Vežba


Za vežbu, probaj da:

  • Pronađeš najkraći put u mreži gradova (kao GPS)
  • Napraviš program koji vraća sve čvorove na rastojanju ≤ K
  • Implementiraš obrnuti algoritam: traženje najdaljeg čvora


Sledeća preporučena lekcija


□ Nastavljamo sa minimalnim razapinjućim stablima:

Bellman-Ford i Floyd-Warshall algoritmi



Vraćanje na vodič za oblast "Grafovi i stabla"

← Mapa učenja — Grafovi i stabla