Algorytm Dijkstry

From Nasza Pasja - Programowanie

Algorytm służy do znajdowania najkrótszych ścieżek w grafie skierowanym.

Zapis w pseudokodzie

Dla grafu G, funkcji wagowej w i wierzchołka s, otrzymamy tablicę d[u] odległości każdego wierzchołka grafu od wierzchołka s.

W tym zapisie funkcja u := Wyjmij_Min(Q) poszukuje wierzchołka u w zbiorze Q, mającego najmniejszą wartość d[u]. Ten wierzchołek jest usuwany ze zbioru Q i zwracany przez funkcję.

Dijkstra(G,w,s):

dla każdego wierzchołka v w V[G] wykonaj
  d[v] = nieskończone
  poprzednik[v] = niezdefiniowane
d[s] = 0
S = zbiór pusty
Q = zbiór wszystkich wierzchołków
dopóki Q nie jest zbiorem pustym wykonaj
  u = Wyjmij_Min(Q)
  S = suma zbiorów S i {u}
  dla każdego wierzchołka v, który jest sąsiedni do u wykonaj
    jeżeli d[v] > d[u] + w(u,v) to
      d[v] = d[u] + w(u,v)
      poprzednik[v] = u

Implemenacja w C++

Program pobiera dane ze standardowego wejścia i wypisuje je na standardowe wyjście

Wejście. Pierwszą informacją na wejściu powinny być dwie liczby:

e n

gdzie e - liczba wierzchołków i n - liczba krawędzi. Następnie powinno wystąpić n trójek liczb:

a b c

gdzie a - numer pierwszego wierzchołka, b - numer drugiego wierzołka, c odległość między nimi.

Wyjście. Program zwraca e liczb, gdzie e-ta liczba to najkrótsza ścieżka między wierzchołkiem o numerze 1 i wierchołkiem o numerze e

// Autor: comboy

#include <iostream.h>

long long int ODLEGLOSC_MAX = 1000000001;
int rozmiar;

class element
{
        public:
        int numer;
        int waga;
        element *nastepny;

        element(int numerek, int wagus)
        {
                numer = numerek;
                waga = wagus;
        }
};

class lista
{
        public:
        element *glowa;
        element *ogon;

        void dopisz(int numer, int waga);

        lista()
        {
                glowa = NULL;
                ogon = NULL;
        }
};

void lista::dopisz(int numer, int waga)
{

        element *nowy=new element(numer,waga);

        if (glowa==NULL)
        {
                glowa = ogon = nowy;
        } else
        {
                ogon->nastepny = nowy;
                ogon = nowy;
        }

}

class wierzcholek
{
        public:
        bool obliczony;
        lista polaczenia;
        int kop_nr;
};

class wezel
{
        public:
        long long int odleglosc;
        int graf_nr;
};

wierzcholek graf[100000];
wezel kopiec[100000];

void zamien_kop(int numer1, int numer2)
{
        wezel tmp;
        tmp = kopiec[numer1];
        kopiec[numer1] = kopiec[numer2];
        kopiec[numer2] = tmp;
        graf[kopiec[numer2].graf_nr].kop_nr = numer2;
        graf[kopiec[numer1].graf_nr].kop_nr = numer1;
}

void uporzadkuj_wezel(int numer)
{
        int lewy=numer*2;
        int prawy=numer*2+1;
        int min;

        if (lewy<=rozmiar && kopiec[lewy].odleglosc<kopiec[numer].odleglosc)
        {
                min = lewy;
        } else min = numer;
        if (prawy<=rozmiar && kopiec[prawy].odleglosc<kopiec[min].odleglosc) min = prawy;

        if (numer!=min)
        {
                zamien_kop(numer,min);
                uporzadkuj_wezel(min);
        }
}



int main()
{

        int n;
        int e;

        cin >> n >> e;

        int a;
        int b;
        int w;

        // Usypanie kopca

        for (int i=1; i<=n; i++)
        {
                graf[i].kop_nr = i;
                kopiec[i].graf_nr = i;
                kopiec[i].odleglosc = ODLEGLOSC_MAX;
        }

        // Wczytywanie danych

        for(int i=0; i<e; i++)
        {
                cin >> a >> b >> w;
                graf[a].polaczenia.dopisz(b,w);
        }

        rozmiar = n;
        kopiec[0].odleglosc = -1;
        kopiec[1].odleglosc = 0;



        while (rozmiar>0)
        {
                element *temp;
                if (graf[kopiec[1].graf_nr].polaczenia.glowa!=NULL)
                {
                        temp = graf[kopiec[1].graf_nr].polaczenia.glowa;
                        while (temp!=NULL)
                        {
                                if (kopiec[graf[temp->numer].kop_nr].odleglosc > (temp->waga + kopiec[1].odleglosc))
                                {
                                        kopiec[graf[temp->numer].kop_nr].odleglosc = temp->waga + kopiec[1].odleglosc;
                                        int i=graf[temp->numer].kop_nr;
                                        while (kopiec[int(i/2)].odleglosc > kopiec[i].odleglosc)
                                        {
                                                zamien_kop(int(i/2),i);
                                                i = i/2;
                                        } // i pojechal sobie do gory
                                }
                                temp = temp->nastepny;
                        }
                }
                // A teraz najlepsze: scinamy kopcowi korzen :]
                zamien_kop(1,rozmiar+1);
                uporzadkuj_wezel(1);
                rozmiar--;
        }


        for (int i=1; i<=n; i++)
        {
                if (kopiec[graf[i].kop_nr].odleglosc == 1000000001)
                {
                        cout << "NIE" << endl;
                } else
                {
                        cout << kopiec[graf[i].kop_nr].odleglosc << endl;
                }

        }


}