Wyszukiwanie najkrótszej drogi między parą wierzchołków w grafie
Algorytm Floyda-Warshalla w przeciwieństwie do algorytmu Dijkstry można było zastosować w grafach z ujemnymi wagami krawędzi, warunkiem było aby w grafie nie występowały ujemne pętle.
Algorytm Dijkstry jest algorytmem zachłannym czyli w celu wyznaczenia rozwiązania w każdym kroku dokonuje zachłannego, najlepiej rokującego w danej chwili rozwiązania częściowego. Podczas pracy algorytmu nie jest dokonywana ocena odnośnie całokształtu jedynie ocena lokalna i wybierane jest rozwiązanie lokalnie optymalne.
Przykładowe zastosowanie algorytmu Dijkstry
Algorytm ten może być wykorzystywany przy obliczaniu najkrótszej drogi na mapie zakładając, że każde skrzyżowanie to wierzchołek a odległości między nimi to wagi. Również jest wykorzystywany przy trasowaniu w sieciach komputerowych w protokole OSPF (wiki).
Działanie algorytmu
Algorytm polega na wybieraniu drogi, która w danej chwili ma najniższy koszt. Startując z wierzchołka s szukamy wagi która jest najniższa i przechodzimy do wierzchołka po tej krawędzi.
Algorytm ten również ma złożoność O(n2) zaś Floyda-Warshalla O(n3). Również jego zaletą jest to, że nie są obliczane wszystkie odległości tylko wyszukiwana ta do celu, dzięki czemu może algorytm zakończyć się wcześniej, co nie ma miejsca w Floydzie-Warshallu. Również tam gdzie graf się zmienia warto rozważyć ten algorytm, przy niezmiennych Floyd-Warshall.
Implementacja kodu
Do testowania implementacji zastosujemy ten sam graf co w algorytmie Floyda-Warshalla:
using System; namespace Dijkstra { class Program { static void Main(string[] args) { Console.WriteLine("Przykładowa implementacja algorytmu Dijkstry"); //przygotowanie danych //utworzenie tablicy int rozmiar_tablicy = 5; //ilosc wierzchołków grafu var tablica = new int[rozmiar_tablicy, rozmiar_tablicy]; //wypełnienie tablicy for (int i = 0; i < rozmiar_tablicy; i++) for (int j = 0; j < rozmiar_tablicy; j++) { tablica[i, j] = Dijkstra.INFINITI; } //uzupełnienie macierzy sąsiedztwa //tablica zaharkodowana, najlepiej by było przekazywać macierz jako parametr tablica[0, 1] = 2; tablica[0, 2] = 3; tablica[1, 3] = 3; tablica[1, 4] = 7; tablica[2, 3] = 4; tablica[3, 4] = 1; //utworzenie instancji klasy var dijkstra = new Dijkstra(tablica); //pobranie ścieżki między wierzchołkami podanymi w parametrze metody var test = dijkstra.GetPath(0, 4); foreach (var item in test) { Console.WriteLine(item.ToString()); }; Console.ReadLine(); } class Dijkstra { //stała - nieskończoność public const int INFINITI = int.MaxValue; public int[,] Tablica { get; set; } public Dijkstra(int[,] tablica) { Tablica = tablica; } public int[] GetPath(int start, int meta) { int rozmiarTablicy = Tablica.GetLength(0); int[] odleglosc = new int[rozmiarTablicy]; int[] poprzednik = new int[rozmiarTablicy]; int[] wezel = new int[rozmiarTablicy]; for (int i = 0; i < odleglosc.Length; i++) { odleglosc[i] = poprzednik[i] = INFINITI; wezel[i] = i; } odleglosc[start] = 0; do { int najmniejszy = wezel[0]; int najmniejszyIndex = 0; for (int i = 0; i < rozmiarTablicy; i++) { if (odleglosc[wezel[i]] < odleglosc[najmniejszy]) { najmniejszy = wezel[i]; najmniejszyIndex = i; } } rozmiarTablicy--; wezel[najmniejszyIndex] = wezel[rozmiarTablicy]; if (odleglosc[najmniejszy] == INFINITI || najmniejszy == meta) { break; } for (int i = 0; i < rozmiarTablicy; i++) { int j = wezel[i]; int nowaOdleglosc = odleglosc[najmniejszy] + Tablica[najmniejszy, j]; if (nowaOdleglosc < odleglosc[j]) { odleglosc[j] = nowaOdleglosc; poprzednik[j] = najmniejszy; } } } while (rozmiarTablicy > 0); return RekonstruktorSciezki(poprzednik, start, meta); } public int[] RekonstruktorSciezki(int[] prev, int start, int meta) { int[] ret = new int[prev.Length]; int currentNode = 0; ret[currentNode] = meta; while (ret[currentNode] != INFINITI && ret[currentNode] != start) { ret[currentNode + 1] = prev[ret[currentNode]]; currentNode++; } if (ret[currentNode] != start) return null; int[] reversed = new int[currentNode + 1]; for (int i = currentNode; i >= 0; i--) reversed[currentNode - i] = ret[i]; return reversed; } } } }