Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

Materiały dla uczniów liceum

  Wyjście       Spis treści       Wstecz       Dalej  

Autor artykułu: mgr Jerzy Wałaszek

©2026 mgr Jerzy Wałaszek

Najkrótsze ścieżki pomiędzy wszystkimi parami wierzchołków w grafie ważonym
Algorytm Floyda-Warshalla

SPIS TREŚCI
Podrozdziały

Problem

W spójnym grafie ważonym należy znaleźć wagi najkrótszych ścieżek pomiędzy wszystkimi parami wierzchołków.

Wersja podstawowa

Zadanie to rozwiązuje algorytm Floyda-Warshalla. Działa on w sposób dynamiczny i opiera się na spostrzeżeniu, że jeśli koszt dojścia z wierzchołka v do u jest większy od sumy kosztów dojść z wierzchołka v do k i z k do u, to za lepszy koszt należy przyjąć tę nową, mniejszą wartość.

obrazek

Przetwarzany graf może posiadać krawędzie o wagach ujemnych, jednakże nie mogą w nim występować cykle ujemne (ang. negative cycles –  cykle, w których suma wag krawędzi jest ujemna). Algorytm Floyda-Warshalla może takie cykle wykrywać.

Algorytm w podstawowej wersji tworzy macierz d o rozmiarze n × n. Element d[i,j] tej macierzy będzie oznaczał najniższy koszt dojścia od wierzchołka i-tego do j-tego. Po utworzeniu macierzy algorytm wypełniana ją największymi wartościami dodatnimi (plus nieskończoność). Następnie elementy d[i,i], dla i = 0, 1, …, n-1 ustawia na 0. Oznacza to, że koszt dojścia z wierzchołka i-tego do niego samego jest zerowy. Teraz dla każdego wierzchołka grafu k i każdej pary wierzchołków i, j badamy, czy koszt dojścia d[i,j] jest większy od sumy kosztów dojść d[i,k]+d[k,j]. Jeśli tak, to za koszt dojścia d[i,j] przyjmujemy wartość tej sumy (oznacza to, że znaleźliśmy tańsze dojście od wierzchołka i-tego do j-tego poprzez wierzchołek k-ty – zwróć uwagę, że nie oznacza to wcale, że wierzchołki i oraz j muszą łączyć się pojedynczą krawędzią z wierzchołkiem k, po prostu d[i,k] jest minimalnym kosztem ścieżki od i do k, podobnie koszt d[k,j] jest minimalnym kosztem ścieżki od k do j, a koszty te algorytm wyznaczył wcześniej i teraz z nich korzysta – zasada programowania dynamicznego!). Operacja ta wymaga trzech zagnieżdżonych pętli dla k, i, j. Z tego powodu algorytm Floyda-Warshalla ma klasę złożoności obliczeniowej równą O(n3), gdzie n oznacza liczbę wierzchołków w grafie. Złożoność pamięciowa wynosi O(n2).

Prześledźmy na prostym przykładzie działanie tego algorytmu.

obrazek
d 0 1 2 3 4
0 0
1 0
2 0
3 0
4 0
Oto nasz graf ważony z ujemnymi wagami
krawędzi. Przygotowujemy macierz d.
Na głównej przekątnej umieszczamy 0, a w
pozostałych komórkach umieszczamy ∞.
obrazek
d 0 1 2 3 4
0 0 5 4 8
1 -4 0 -2 5
2 0 5 2
3 -1 2 0 -1
4 4 2 0
Następnie dla każdej krawędzi uv grafu
w komórce d[u,v] umieszczamy wagę
krawędzi w (uv). Wartość d[i,j] = ∞
oznacza, że wierzchołek i-ty nie łączy się
krawędzią z wierzchołkiem j-tym (ale, jak
zobaczymy dalej, może istnieć ścieżka
łącząca te wierzchołki, a wtedy algorytm
wprowadzi do d[i,j] jej koszt)
.
obrazek
d 0 1 2 3 4
0 0 5 4 8
1 -4 0 -2 4 5
2 0 5 2
3 -1 2 3 0 -1
4 4 2 0
Rozpoczynamy przeglądanie kolejnych
wierzchołków grafu od wierzchołka k = 0.
Dla każdej pary wierzchołków u, v
sprawdzamy, czy zachodzi nierówność:
d[u,v] > d[u,k]+d[k,v].
Jeśli tak, to d[u,v] ← d[u,k] + d[k,v].
W tym przypadku nierówność będzie
spełniona dla par wierzchołków:
(1,3): d[1,3] = ∞ > d[1,0]+d[0,3] = -4+8 = 4
(3,2): d[3,2] = ∞ > d[3,0]+d[0,2] = -1+4 = 3
Zmieniamy dla nich wpisy w macierzy d:
d[1,3] ← 4
d[3,2] ← 3
obrazek
d 0 1 2 3 4
0 0 5 3 8 10
1 -4 0 -2 4 5
2 0 5 2
3 -2 2 0 0 -1
4 4 2 0
Idziemy do następnego wierzchołka grafu,
k = 1. Znów sprawdzamy podaną wyżej
nierówność dla wszystkich par
wierzchołków w grafie. Będzie spełniona
dla p:
(0,2): d[0,2] =  4 > d[0,1]+d[1,2] = 5+-2 =   3
(0,4): d[0,4] = ∞ > d[0,1]+d[1,4] = 5+ 5 = 10
(3,0): d[3,0] = -1 > d[3,1]+d[1,0] = 2+-4 = -2
(3,2): d[3,2] =   3 > d[3,1]+d[1,2] = 2+-2 =   0
Ustawiamy:
d[0,2] ← 3
d[0,4] ← 10
d[3, 0] ← -2
d[3, 2] ← 0
obrazek
d 0 1 2 3 4
0 0 5 3 8 5
1 -4 0 -2 3 0
2 0 5 2
3 -2 2 0 0 -1
4 4 2 0
Następny wierzchołek, k = 2. Nierówność
jest spełniona dla następujących par
wierzchołków:
(0,4): d[0,4] = 10 > d[0,2]+d[2,4] =  3+2 = 5
(1,3): d[1,3] =   4 > d[1,2]+d[2,3] = -2+5 = 3
(1,4): d[1,4] =   5 > d[1,2]+d[2,4] = -2+2 = 0
Ustawiamy:
d[0,4] ← 5
d[1,3] ← 3
d[1,4] ← 0
obrazek
d 0 1 2 3 4
0 0 5 3 8 5
1 -4 0 -2 3 0
2 3 7 0 5 2
3 -2 2 0 0 -1
4 0 4 2 2 0
Następny wierzchołek, k = 3.
(2,0): d[2,0] = ∞ > d[2,3]+d[3,0] = 5+-2 = 3
(2,1): d[2,1] = ∞ > d[2,3]+d[3,1] = 5+  2 = 7
(4,0): d[4,0] = ∞ > d[4,3]+d[3,0] = 2+-2 = 0
(4,1): d[4,1] = ∞ > d[4,3]+d[3,1] = 2+  2 = 4
(4,2): d[4,2] =   4 > d[4,3]+d[3,2] = 2+  0 = 2
Ustawiamy:
d[2,0] ← 3
d[2,1] ← 7
d[4,0] ← 0
d[4,1] ← 4
d[4,2] ← 2
obrazek
d 0 1 2 3 4
0 0 5 3 7 5
1 -4 0 -2 2 0
2 2 6 0 4 2
3 -2 2 0 0 -1
4 0 4 2 2 0
Ostatni wierzchołek, k = 4.
(0,3): d[0,3] = 8 > d[0,4]+d[4,3] = 5+2 = 7
(1,3): d[1,3] = 3 > d[1,4]+d[4,3] = 0+2 = 2
(2,0): d[2,0] = 3 > d[2,4]+d[4,0] = 2+0 = 2
(2,1): d[2,1] = 7 > d[2,4]+d[4,1] = 2+4 = 6
(2,3): d[2,3] = 5 > d[2,4]+d[4,3] = 2+2 = 4
Ustawiamy:
d[0,3] ← 7
d[1,3] ← 2
d[2,0] ← 2
d[2,1] ← 6
d[2,3] ← 4

Koszty dojść są następujące:

d[0,0] =  0
d[0,1] =  5
d[0,2] =  3
d[0,3] =  7
d[0,4] =  5
d[1,0] = -4
d[1,1] =  0
d[1,2] = -2
d[1,3] =  2
d[1,4] =  0
d[2,0] =  2
d[2,1] =  6
d[2,2] =  0
d[2,3] =  4
d[2,4] =  2
d[3,0] = -2
d[3,1] =  2
d[3,2] =  0
d[3,3] =  0
d[3,4] = -1
d[4,0] =  0
d[4,1] =  4
d[4,2] =  2
d[4,3] =  2
d[4,4] =  0

Algorytm Floyda-Warshalla znajdowania najmniejszych kosztów dojścia pomiędzy wszystkimi parami wierzchołków grafu ważonego

Wejście:

n : liczba wierzchołków w grafie; n ∈ C.
graf : zadany w dowolnie wybrany sposób, algorytm tego nie precyzuje.

Wyjście:

d : n × n elementowa macierz kosztów dojścia. Element d[i,j] oznacza minimalny koszt dojścia z wierzchołka i-tego do j-tego.

Elementy pomocnicze:

k,i,j : numery wierzchołków w grafie;  k,i,j ∈ C.

Lista kroków:

K01: Utwórz macierz d
     o rozmiarze n × n
K02: Dla i = 0, 1, …, n-1:
     wykonuj kroki K03…K05
K03:   Dla j = 0, 1, …, n-1: ; ustawiamy wszystkie
       wykonuj: d[i,j] ← ∞ ; komórki na nieskończoność 
K04:   d[i,i] ← 0 ; elementy głównej przekątnej zerujemy
K05:   Dla każdego sąsiada j wierzchołka i: ; ustawiamy w d wagi krawędzi
       wykonuj:
         d[i,j] ← waga krawędzi ij
K06: Dla k = 0, 1, …, n-1, ; przechodzimy przez
     wykonuj kroki K07…K09 ; wszystkie wierzchołki grafu
K07:   Dla i = 0, 1, …, n-1, ; wybieramy wszystkie pary
       wykonuj kroki K08…K09 ; i, j wierzchołków w grafie
K08:     Dla j = 0, 1, …, n-1, 
         wykonuj krok K09
K09:       Jeśli d[i,j] > d[i,k]+d[k,j], ; testujemy nierówność i,
           to: d[i,j] ← d[i,k]+d[k,j] ; jeśli jest spełniona, modyfikujemy koszt
K10: Zakończ z wynikiem d

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Poniższy program najniższe koszty dojścia dla wszystkich par wierzchołków w grafie za pomocą algorytmu Floyda-Warshalla. Definicja danych wejściowych jest następująca:

W pierwszym wierszu program odczytuje kolejno liczbę wierzchołków n oraz liczbę krawędzi m. W m kolejnych wierszach znajdują się definicje krawędzi. Definicja składa się z trzech liczb x y w. Pierwsza liczba x oznacza początek krawędzi, druga liczba y oznacza koniec krawędzi, a trzecia liczba w jest wagą tej krawędzi.

Na wyjściu program wypisuje koszt najkrótszej ścieżki pomiędzy każdymi dwoma wierzchołkami grafu. Jeśli ścieżka nie istnieje, pojawia się napis "NO PATH".
Dane przykładowe (przekopiuj do schowka i wklej do okna konsoli):
obrazek 5 13
0 1 5
0 2 4
0 3 8
1 0 -4
1 2 -2
1 4 5
2 3 5
2 4 2
3 0 -1
3 1 2
3 4 -1
4 2 4
4 3 2
Pascal
// Algorytm Floyda-Warshalla
// Data: 20.04.2014
// (C)2014 mgr Jerzy Wałaszek
//---------------------------

program floyd_warshall;

// Typ danych
// dla macierzy dynamicznej
type
  nptr = array of integer;

var
  // Macierz minimalnych
  // kosztów dojścia
  d : array of nptr;
  i,j,k,n,m,x,y,w : integer;
begin
  // Czytamy liczbę
  // wierzchołków oraz krawędzi
  read(n, m);
  // Tworzymy dynamiczną
  // macierz d
  SetLength(d, n);
  for i := 0 to n-1 do
  begin
    // Tworzymy wiersz macierzy
    SetLength(d[i], n);
    for j := 0 to n-1 do
      // Wiersz wypełniamy
      // największą liczbą
      // dodatnią
      d[i][j] := MAXINT;
    // Jednakże na przekątnej
    // wpisujemy 0
    d[i][i] := 0;
  end;
  for i := 1 to m do
  begin
    // Czytamy definicję krawędzi
    read(x, y, w);
    // Wagę krawędzi
    // umieszczamy w macierzy d
    d[x][y] := w;
  end;
  // Algorytm Floyda-Warshalla
  for k := 0 to n-1 do
    for i := 0 to n-1 do
      for j := 0 to n-1 do
      begin
        if (d[i][k] = MAXINT) or
           (d[k][j] = MAXINT) then
          continue;
        w := d[i][k]+d[k][j];
        if d[i][j] > w then
          d[i][j] := w;
      end;
  // Wyświetlamy wyniki
  writeln;
  for i := 0 to n-1 do
    for j := 0 to n-1 do
    begin
      write('d[',i,',',j,'] = ');
      if d[i][j] = MAXINT then
        writeln('NO PATH')
      else
        writeln(d[i][j]);
    end;
  // Usuwamy macierz dynamiczną
  for i := 0 to n-1 do
    SetLength(d[i], 0);
  SetLength(d, 0);
end.
C++
// Algorytm Floyda-Warshalla
// Data: 20.04.2014
// (C)2014 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>

using namespace std;

// "plus nieskończoność"
const int MAXINT = 2147483647;

int main()
{
  // Macierz minimalnych
  // kosztów dojścia
  int ** d;
  int i,j,k,n,m,x,y,w;

  // Czytamy liczbę
  // wierzchołków oraz krawędzi
  cin >> n >> m;
  // Tworzymy dynamiczną
  // macierz d
  d = new int * [n];
  for(i = 0; i < n; i++)
  {
    // Tworzymy wiersz macierzy
    d[i] = new int [n];
    for(j = 0; j < n; j++)
      // Wiersz wypełniamy
      // największą liczbą
      // dodatnią
      d[i][j] = MAXINT;
    // Jednakże na przekątnej
    // wpisujemy 0
    d[i][i] = 0;
  }
  for(i = 0; i < m; i++)
  {
    // Czytamy
    // definicję krawędzi
    cin >> x >> y >> w;
    // Wagę krawędzi
    // umieszczamy w macierzy d
    d[x][y] = w;
  }
  // Algorytm Floyda-Warshalla
  for(k = 0; k < n; k++)
    for(i = 0; i < n; i++)
      for(j = 0; j < n; j++)
      {
        if((d[i][k] == MAXINT) ||
           (d[k][j] == MAXINT))
          continue;
        w = d[i][k]+d[k][j];
        if(d[i][j] > w)
          d[i][j] = w;
      }
  // Wyświetlamy wyniki
  cout << endl;
  for(i = 0; i < n; i++)
    for(j = 0; j < n; j++)
    {
      cout << "d[" << i
           << "," << j
           << "] = ";
      if(d[i][j] == MAXINT)
        cout << "NO PATH";
      else
        cout << d[i][j];
      cout << endl;
    }
  // Usuwamy macierz dynamiczną
  for(i = 0; i < n; i++)
    delete [] d[i];
  delete [] d;
  return 0;
}
Basic
' Algorytm Floyda-Warshalla
' Data: 20.04.2014
' (C)2014 mgr Jerzy Wałaszek
'---------------------------

' "plus nieskończoność"
const MAXINT = 2147483647

' Macierz minimalnych
' kosztów dojścia
Dim As Integer Ptr Ptr d
Dim As Integer i,j,k,n,m,x,y,w

Open Cons For Input As #1
' Czytamy liczbę
' wierzchołków
' oraz krawędzi
Input #1, n, m
' Tworzymy
' dynamiczną
' macierz d
d = New Integer Ptr [n]
For i = 0 To n-1
  ' Tworzymy
  ' wiersz macierzy
  d[i] = New Integer [n]
  For j = 0 To n-1
    ' Wiersz wypełniamy
    ' największą liczbą
    ' dodatnią
    d[i][j] = MAXINT
  Next
  ' Jednakże na przekątnej
  ' wpisujemy 0
  d[i][i] = 0
Next
For i = 1 To m
  ' Czytamy definicję krawędzi
  Input #1, x, y, w
  ' Wagę krawędzi
  ' umieszczamy
  ' w macierzy d
  d[x][y] = w
Next
Close #1
' Algorytm Floyda-Warshalla
For k = 0 To n-1
  For i = 0 To n-1
    For j = 0 To n-1
      If (d[i][k] = MAXINT) OrElse _
         (d[k][j] = MAXINT) Then _
        Continue For
      w = d[i][k]+d[k][j]
      If d[i][j] > w Then _
        d[i][j] = w
    Next
  Next
Next 
' Wyświetlamy wyniki
Print
For i = 0 To n-1
  For j = 0 To n-1
    Print Using "d[&,&] =";i;j;
    If d[i][j] = MAXINT Then
      Print " NO PATH"
    Else
      Print d[i][j]
    End If
  Next
Next
' Usuwamy macierz dynamiczną
For i = 0 To n-1
  Delete [] d[i]
Next
Delete [] d
End
Python (dodatek)
# Algorytm Floyda-Warshalla
# Data: 17.02.2025
# (C)2025 mgr Jerzy Wałaszek
#---------------------------

# "plus nieskończoność"
MAXINT = 2147483647
# Czytamy liczbę
# wierzchołków
# oraz krawędzi
z = input().split()
n = int(z[0])
m = int(z[1])
# Tworzymy
# dynamiczną
# macierz d
d = [None] * n
for i in range(n):
    # Tworzymy
    # wiersz macierzy
    d[i] = [MAXINT] * n
    # Na przekątnej
    # wpisujemy 0
    d[i][i] = 0
for i in range(m):
    # Czytamy definicję krawędzi
    z = input().split()
    x = int(z[0])
    y = int(z[1])
    w = int(z[2])
    # Wagę krawędzi
    # umieszczamy
    # w macierzy d
    d[x][y] = w
# Algorytm Floyda-Warshalla
for k in range(n):
    for i in range(n):
        for j in range(n):
            if (d[i][k] == MAXINT) or \
               (d[k][j] == MAXINT):
                continue
            w = d[i][k]+d[k][j]
            if d[i][j] > w:
                d[i][j] = w
# Wyświetlamy wyniki
print()
for i in range(n):
    for j in range(n):
        print("d[",i,",",j,"] = ",
               sep="",end="")
        if d[i][j] == MAXINT:
            print("NO PATH")
        else:
            print(d[i][j])
# Usuwamy macierz dynamiczną
for i in range(n):
    d[i] = None
del d
Wynik:
5 13
0 1 5
0 2 4
0 3 8
1 0 -4
1 2 -2
1 4 5
2 3 5
2 4 2
3 0 -1
3 1 2
3 4 -1
4 2 4
4 3 2

d[0,0] = 0
d[0,1] = 5
d[0,2] = 3
d[0,3] = 7
d[0,4] = 5
d[1,0] = -4
d[1,1] = 0
d[1,2] = -2
d[1,3] = 2
d[1,4] = 0
d[2,0] = 2
d[2,1] = 6
d[2,2] = 0
d[2,3] = 4
d[2,4] = 2
d[3,0] = -2
d[3,1] = 2
d[3,2] = 0
d[3,3] = 0
d[3,4] = -1
d[4,0] = 0
d[4,1] = 4
d[4,2] = 2
d[4,3] = 2
d[4,4] = 0

do podrozdziału  do strony 

Wersja rozszerzona

Podstawowy algorytm Floyda-Warshalla oblicza jedynie minimalne koszty ścieżek pomiędzy wszystkimi parami wierzchołków w grafie ważonym. Nie dostajemy jednakże informacji o samych ścieżkach. Przez prostą modyfikację algorytmu możemy również otrzymać te najkrótsze ścieżki. Najpierw jednak pokażemy, jak rozpoznać w grafie cykl ujemny. Otóż w tym celu wystarczy po zakończeniu działania algorytmu sprawdzić główną przekątną macierzy d. Jeśli jakikolwiek wyraz na głównej przekątnej będzie ujemny, to w grafie mamy cykl ujemny. Wyjaśnienie tego faktu jest proste. Koszt dojścia wierzchołka do siebie samego jest ustawiany na początku algorytmu na zero. Koszt każdego cyklu dodatniego jest większy od zera, zatem przejście przez cykl dodatni i powrót do wierzchołka ma koszt większy od zera i wartość ta nie będzie zmieniona. Jeśli jednak wierzchołek należy do cyklu ujemnego, to przejście przez ten cykl i powrót do wierzchołka daje wartość ujemną, którą zostanie zastąpione to zero. Jeśli graf zawiera cykl ujemny, to nie można w nim wyznaczyć wszystkich najkrótszych ścieżek (każda ścieżka mająca dostęp do takiego cyklu może stać się najkrótszą przez kilkakrotne przejście przez cykl ujemny). Dlatego po rozpoznaniu cyklu ujemnego algorytm powinien zgłosić błąd (np. jeśli realizujemy go w postaci funkcji, to zwraca true, gdy wszystko jest OK, a false, gdy napotka cykl ujemny).

Do zapamiętania ścieżek potrzebujemy dodatkowej macierzy poprzedników p o rozmiarze n × n. W macierzy p element p[u,v] będzie oznaczał poprzednika wierzchołka v na najkrótszej ścieżce. Na początku algorytmu macierz p wypełniamy wartością -1, która oznacza brak poprzednika. Następnie dla każdej krawędzi uv grafu w elemencie p[u,v] umieszczamy u. Teraz w trakcie działania algorytmu Floyda-Warshala w momencie modyfikacji macierzy d modyfikujemy również macierz p. Otóż, gdy spełniona jest nierówność:

d[i,j] > d[i,k] + d[k,j]

i do macierzy d wprowadzamy:

d[i,j] ← d[i,k] + d[k,j]

to wierzchołek k-ty staje się wierzchołkiem pośrednim na najkrótszej ścieżce łączącej wierzchołek i-ty z wierzchołkiem j-tym. Z tego powodu jest on również poprzednikiem wierzchołka j-tego na tej ścieżce. Dlatego w tablicy p umieszczamy wpis:

p[i,j] ← p[k,j]

Wpis ten oznacza poprzednik wierzchołka j-tego na ścieżce wiodącej do wierzchołka k-tego, którego poprzednikiem jest z kolei wierzchołek i-ty.

Odtworzenie poprawnej ścieżki wymaga dodatkowych działań. Po zakończeniu pracy algorytmu Floyda-Warshala najkrótszą ścieżkę pomiędzy wierzchołkami i-tym i j-tym znajdziemy następująco:

Rekurencyjnie szukamy ścieżki od wierzchołka i-tego do j-tego. Najpierw sprawdzamy, czy zachodzi równość i = j. Jeśli tak, to kończymy przez wypisanie i, ponieważ gdy j jest równe i, to jego poprzednikiem jest zawsze i. Następnie sprawdzamy, czy p[i,j] = -1. Jeśli tak, to przerywamy tworzenie ścieżki, ponieważ ona nie istnieje z powodu braku poprzednika. Na koniec, jeśli dwa pierwsze warunki nie będą spełnione, to rekurencyjnie wywołujemy ten sam algorytm dla i oraz p[i,j]. Spowoduje to znalezienie i wypisanie wszystkich kolejnych poprzedników węzła j-tego. Na koniec wypisujemy węzeł j-ty i ścieżka staje się kompletna.

Prześledźmy działanie zmodyfikowanego algorytmu Floyda-Warshala w poniższej tabeli:

obrazek
d 0 1 2 3 4
0 0
1 0
2 0
3 0
4 0
p 0 1 2 3 4
0 -1 -1 -1 -1 -1
1 -1 -1 -1 -1 -1
2 -1 -1 -1 -1 -1
3 -1 -1 -1 -1 -1
4 -1 -1 -1 -1 -1
Oto nasz graf ważony z ujemnymi wagami krawędzi.
Przygotowujemy macierz kosztów dojścia d. Na
głównej przekątnej umieszczamy 0, a w pozostałych
komórkach umieszczamy ∞. Następnie przygotowujemy
macierz poprzedników p. Wszystkie jej komórki wstępnie
ustawiamy na -1.
obrazek
d 0 1 2 3 4
0 0 5 4 8
1 -4 0 -2 5
2 0 5 2
3 -1 2 0 -1
4 4 2 0
p 0 1 2 3 4
0 -1 0 0 0 -1
1 1 -1 1 -1 1
2 -1 -1 -1 2 2
3 3 3 -1 -1 3
4 -1 -1 4 4 -1
Następnie dla każdej krawędzi uv grafu w komórce
d[u,v] umieszczamy wagę krawędzi w (u–v). Wartość
d[i,j] = ∞ oznacza, że wierzchołek i-ty nie łączy się
krawędzią z wierzchołkiem j-tym (ale, jak zobaczymy
dalej, może istnieć ścieżka łącząca te wierzchołki,
a wtedy algorytm wprowadzi do d[i,j] jej koszt)
.
Również modyfikujemy macierz p, umieszczając
w p[u,v] wartość u.
obrazek
d 0 1 2 3 4
0 0 5 4 8
1 -4 0 -2 4 5
2 0 5 2
3 -1 2 3 0 -1
4 4 2 0
p 0 1 2 3 4
0 -1 0 0 0 -1
1 1 -1 1 0 1
2 -1 -1 -1 2 2
3 3 3 0 -1 3
4 -1 -1 4 4 -1
Rozpoczynamy przeglądanie kolejnych
wierzchołków grafu od wierzchołka k = 0. Dla
każdej pary wierzchołków u, v sprawdzamy,
czy zachodzi nierówność:
d[u,v] > d[u,k] + d[k,v].
Jeśli tak, to d[u,v] ← d[u,k] + d[k,v].
W tym przypadku nierówność będzie spełniona
dla par wierzchołków:
(1,3): d[1,3] = ∞ > d[1,0]+d[0,3] = -4+8 = 4
(3,2): d[3,2] = ∞ > d[3,0]+d[0,2] = -1+4 = 3
Zmieniamy dla nich wpisy w macierzach d i p:
d[1,3] ← 4, p[1,3] ← p[0,3] = 0
d[3,2] ← 3, p[3,2] ← p[0,2] = 0
obrazek
d 0 1 2 3 4
0 0 5 3 8 10
1 -4 0 -2 4 5
2 0 5 2
3 -2 2 0 0 -1
4 4 2 0
p 0 1 2 3 4
0 -1 0 1 0 1
1 1 -1 1 0 1
2 -1 -1 -1 2 2
3 1 3 1 -1 3
4 -1 -1 4 4 -1
Idziemy do następnego wierzchołka grafu, k = 1.
Znów sprawdzamy podaną wyżej nierówność dla
wszystkich par wierzchołków w grafie. Będzie
spełniona dla par:
(0,2): d[0,2] =   4 > d[0,1]+d[1,2] = 5+-2 =   3
(0,4): d[0,4] = ∞ > d[0,1]+d[1,4] = 5+  5 = 10
(3,0): d[3,0] = -1 > d[3,1]+d[1,0] = 2+-4 =  -2
(3,2): d[3,2] =   3 > d[3,1]+d[1,2] = 2+-2 =   0
Ustawiamy:
d[0,2] ←   3, p[0,2] ← p[1,2] = 1
d[0,4] ← 10, p[0,4] ← p[1,4] = 1
d[3,0] ←  -2, p[3,0] ← p[1,0] = 1
d[3,2] ←    0, p[3,2] ← p[3,2] = 1
obrazek
d 0 1 2 3 4
0 0 5 3 8 5
1 -4 0 -2 3 0
2 0 5 2
3 -2 2 0 0 -1
4 4 2 0
p 0 1 2 3 4
0 -1 0 1 0 2
1 1 -1 1 2 2
2 -1 -1 -1 2 2
3 1 3 1 -1 3
4 -1 -1 4 4 -1
Następny wierzchołek, k = 2. Nierówność jest
spełniona dla następujących par wierzchołków:
(0,4): d[0,4] = 10 > d[0,2]+d[2,4] =  3+2 = 5
(1,3): d[1,3] =   4 > d[1,2]+d[2,3] = -2+5 = 3
(1,4): d[1,4] =   5 > d[1,2]+d[2,4] = -2+2 = 0
Ustawiamy:
d[0,4] ← 5, p[0,4] ← p[2,4] = 2
d[1,3] ← 3, p[1,3] ← p[2,3] = 2
d[1,4] ← 0, p[1,4] ← p[1,4] = 2
obrazek
d 0 1 2 3 4
0 0 5 3 8 5
1 -4 0 -2 3 0
2 3 7 0 5 2
3 -2 2 0 0 -1
4 0 4 2 2 0
p 0 1 2 3 4
0 -1 0 1 0 2
1 1 -1 1 2 2
2 1 3 -1 2 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Następny wierzchołek, k = 3.
(2,0): d[2,0] = ∞ > d[2,3]+d[3,0] = 5+-2 = 3
(2,1): d[2,1] = ∞ > d[2,3]+d[3,1] = 5+  2 = 7
(4,0): d[4,0] = ∞ > d[4,3]+d[3,0] = 2+-2 = 0
(4,1): d[4,1] = ∞ > d[4,3]+d[3,1] = 2+  2 = 4
(4,2): d[4,2] =   4 > d[4,3]+d[3,2] = 2+  0 = 2
Ustawiamy:
d[2,0] ← 3, p[2,0] ← p[3,0] = 1
d[2,1] ← 7, p[2,1] ← p[3,1] = 3
d[4,0] ← 0, p[4,0] ← p[3,0] = 1
d[4,1] ← 4, p[4,1] ← p[3,1] = 3
d[4,2] ← 2, p[4,2] ← p[3,2] = 1
obrazek
d 0 1 2 3 4
0 0 5 3 7 5
1 -4 0 -2 2 0
2 2 6 0 4 2
3 -2 2 0 0 -1
4 0 4 2 2 0
p 0 1 2 3 4
0 -1 0 1 4 2
1 1 -1 1 4 2
2 1 3 -1 4 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Ostatni wierzchołek, k = 4.
(0,3): d[0,3] = 8 > d[0,4]+d[4,3] = 5+2 = 7
(1,3): d[1,3] = 3 > d[1,4]+d[4,3] = 0+2 = 2
(2,0): d[2,0] = 3 > d[2,4]+d[4,0] = 2+0 = 2
(2,1): d[2,1] = 7 > d[2,4]+d[4,1] = 2+4 = 6
(2,3): d[2,3] = 5 > d[2,4]+d[4,3] = 2+2 = 4
Ustawiamy:
d[0,3] ← 7, p[0,3] ← p[4,3] = 4
d[1,3] ← 2, p[1,3] ← p[4,3] = 4
d[2,0] ← 2, p[2,0] ← p[4,0] = 1
d[2,1] ← 6, p[2,1] ← p[4,1] = 3
d[2,3] ← 4, p[2,3] ← p[4,3] = 4

Teraz pokażemy, jak wydobyć rekurencyjnie z macierzy p informację o najkrótszej ścieżce. Załóżmy, że chcemy odczytać najkrótszą ścieżkę od wierzchołka 4 do 2:

obrazek
p 0 1 2 3 4
0 -1 0 1 4 2
1 1 -1 1 4 2
2 1 3 -1 4 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Wy:
Poziom rekurencji 0:
i = 4, j = 2
Ponieważ i nie jest równe j oraz p[4,2] jest różne od -1,
to wywołujemy rekurencyjnie ten sam algorytm z parametrami:
i = 4, j = p[4,2] = 1.
Powrót nastąpi w to miejsce, gdzie wypiszemy j
i zakończymy algorytm.
obrazek
p 0 1 2 3 4
0 -1 0 1 4 2
1 1 -1 1 4 2
2 1 3 -1 4 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Wy:
Poziom rekurencji 1:
i = 4, j = 1
Wywołujemy rekurencyjnie ten sam algorytm z parametrami:
i = 4, j = p[4,1] = 3.
obrazek
p 0 1 2 3 4
0 -1 0 1 4 2
1 1 -1 1 4 2
2 1 3 -1 4 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Wy:
Poziom rekurencji 2:
i = 4, j = 3
Wywołujemy rekurencyjnie ten sam algorytm z parametrami:
i = 4, j = p[4,3] = 4.
obrazek
p 0 1 2 3 4
0 -1 0 1 4 2
1 1 -1 1 4 2
2 1 3 -1 4 2
3 1 3 1 -1 3
4 1 3 1 4 -1
Wy: 4
Poziom rekurencji 3:
i = 4, j = 4
Zachodzi równość i = j. Wypisujemy 4 i wracamy na poziom 2.
obrazek Wy: 4 3 Poziom rekurencji 2:
i = 4, j = 3
Po powrocie z wywołania rekurencyjnego na poziomie 3
wypisujemy j i wracamy na poziom 1.
obrazek Wy: 4 3 1 Poziom rekurencji 1:
i = 4, j = 1
Po powrocie z wywołania rekurencyjnego na poziomie 2
wypisujemy j i wracamy na poziom 0.
obrazek Wy: 4 3 1 2 Poziom rekurencji 0:
i
= 4, j = 2
Po powrocie z wywołania rekurencyjnego na poziomie 1
wypisujemy j i kończymy algorytm. Ścieżka jest gotowa.

Algorytm rozszerzony Floyda-Warshalla

Wejście:

n : liczba wierzchołków w grafie; n ∈ C.
graf : zadany w dowolnie wybrany sposób, algorytm tego nie precyzuje.

Wyjście:

true – poprawne zakończenie, wynikiem są zawartości dwóch macierzy:

d : n × n elementowa macierz kosztów dojścia. Element d[i,j] oznacza minimalny koszt dojścia z wierzchołka i-tego do j-tego.
p : n × n elementowa macierz poprzedników. Element p[i,j] oznacza poprzednik wierzchołka j-tego na minimalnej ścieżce od wierzchołka i-tego do j-tego.

false – graf zawiera cykl ujemny.

Elementy pomocnicze:

k,i,j : numery wierzchołków w grafie; k,i,j ∈ C.

Lista kroków:

K01: Utwórz macierze d i p o rozmiarze n×n
K02: Dla i = 0, 1, …, n-1:
     wykonuj kroki K03…K05
K03:   Dla j = 0, 1, …, n-1, ; ustawiamy wszystkie komórki d
       wykonuj: ; na nieskończoność, a wszystkie komórki p na -1
         d[i,j] ← ∞
         p[i,j] ← -1
K04:   d[i,i] ← 0 ; elementy głównej przekątnej zerujemy
K05:   Dla każdego sąsiada j wierzchołka i, ; ustawiamy w d wagi
       wykonuj: ;  krawędzi, a w p poprzedniki wierzchołków j-tych
         d[i,j] ← waga krawędzi ij
         p[i,j] ← i
K06: Dla k = 0, 1, …, n-1, ; przechodzimy przez wszystkie
     wykonuj kroki K07…K09 ; wierzchołki grafu
K07:   Dla i = 0, 1, …, n-1, ; wybieramy wszystkie pary
       wykonuj kroki K08…K09 ; i, j wierzchołków w grafie
K08:     Dla j = 0, 1, …, n-1, ; 
         wykonuj krok K09
K09:       Jeśli d[i,j] > d[i,k]+d[k,j], ; testujemy nierówność i,
           to: ; jeśli jest spełniona, modyfikujemy koszt.
             d[i,j] ← d[i,k]+d[k,j] ; Jako poprzednik j na ścieżce od i do j
             p[i,j] ← p[k,j] ; ustawiamy poprzednik j na ścieżce od k do j.
K10: Dla i = 0, 1, …, n-1:
     wykonuj:
       Jeśli d[i,i] = -1, ; wykryto cykl ujemny
       to zakończ z wynikiem false
K11: Zakończ z wynikiem true

Algorytm rekurencyjnej procedury rekonstrukcji ścieżki z macierzy poprzedników p

FWPath(p,i,j)

Wejście:

p : n×n elementowa macierz poprzedników. Element p[i,j] oznacza poprzednik wierzchołka j-tego na minimalnej ścieżce od wierzchołka i-tego do j-tego.
i : wierzchołek startowy krawędzi; i ∈ C.
j : wierzchołek końcowy krawędzi; j ∈ C.

Wyjście:

minimalna ścieżka od wierzchołka i-tego do j-tego lub napis "NO PATH", jeśli taka ścieżka nie istnieje

Lista kroków:

K01: Jeśli i = j, 
     to pisz i
     i zakończ
K02: Jeśli p[i,j] = -1, 
     to pisz "NO PATH"
     i zakończ
K03: FWPath(p,i,p[i,j]) ; wywołanie rekurencyjne
K04: Pisz j ; ostatni wierzchołek ścieżki
K05: Zakończ

Przykładowe programy

Uwaga:

Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich.

Poniższy wyznacza ścieżki o najniższym koszcie dojścia dla wszystkich par wierzchołków w grafie za pomocą rozszerzonego algorytmu Floyda-Warshalla. Definicja danych wejściowych jest następująca:

W pierwszym wierszu program odczytuje kolejno liczbę wierzchołków n oraz liczbę krawędzi m. W m kolejnych wierszach znajdują się definicje krawędzi. Definicja składa się z trzech liczb x y w. Pierwsza liczba x oznacza początek krawędzi, druga liczba y oznacza koniec krawędzi, a trzecia liczba w jest wagą tej krawędzi.

Na wyjściu dla każdej pary wierzchołków program wypisuje minimalną ścieżkę oraz jej koszt. Jeśli ścieżka nie istnieje, pojawia się napis "NO PATH".
Dane przykładowe (przekopiuj do schowka i wklej do okna konsoli):
obrazek 5 13
0 1 5
0 2 4
0 3 8
1 0 -4
1 2 -2
1 4 5
2 3 5
2 4 2
3 0 -1
3 1 2
3 4 -1
4 2 4
4 3 2
Pascal
// Algorytm Floyda-Warshalla
// Data: 21.04.2014
// (C)2014 mgr Jerzy Wałaszek
//---------------------------

program floyd_warshall2;

// Typ danych dla
// macierzy dynamicznej
type
  nptr = array of integer;

// Zmienne globalne
var
  // Macierze kosztów
  // oraz poprzedników
  d, p : array of nptr;
  // Liczba wierzchołków
  // i krawędzi
  n, m : integer;

// Funkcja wyznaczania
// kosztów dojścia oraz
// minimalnych ścieżek
// w grafie ważonym
//---------------------
function FloydWarshall : boolean;
var
  i, j, k, w : integer;

begin
  for k := 0 to n-1 do
    for i := 0 to n-1 do
      for j := 0 to n-1 do
      begin
        if (d[i][k] = MAXINT) or
           (d[k][j] = MAXINT) then
          continue;
        w := d[i][k] + d[k][j];
        if d[i][j] > w then
        begin
          d[i][j] := w;
          p[i][j] := p[k][j];
        end;
      end;
  for i := 0 to n-1 do
    if d[i][i] < 0 then
      // Ujemny cykl
      Exit(false);
  FloydWarshall := true;
end;

// Rekurencyjna procedura
// odtwarzania minimalnej
// ścieżki z macierzy
// poprzedników p
//-----------------------
procedure FWPath(i, j : integer);
begin
  if i = j then
    write(i, ' ')
  else if p[i][j] = -1 then
    write('NO PATH')
  else
  begin
    FWPath(i, p[i][j]);
    write (j, ' ');
  end;
end;

// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
var
  i, j, x, y, w : integer;
begin
  // Czytamy liczbę
  // wierzchołków oraz
  // krawędzi
  read(n, m);
  // Tworzymy dynamiczną
  // macierz d
  SetLength(d, n);
  // Tworzymy dynamiczną
  // macierz p
  SetLength(p, n);
  for i := 0 to n-1 do
  begin
    // Tworzymy wiersz
    // macierzy d
    SetLength(d[i], n);
    // Tworzymy wiersz
    // macierzy p
    SetLength(p[i], n);
    for j := 0 to n-1 do
    begin
      // Wiersz d wypełniamy
      // największą liczbą
      // dodatnią
      d[i][j] := MAXINT;
      // Wiersz p wypełniamy
      // liczbami -1
      // (brak poprzednika)
      p[i][j] := -1;
    end;
    // Jednakże na przekątnej d
    // wpisujemy 0
    d[i][i] := 0;
  end;
  for i := 1 to m do
  begin
    // Czytamy definicję
    // krawędzi
    read(x, y, w);
    // Wagę krawędzi
    // umieszczamy
    // w macierzy d
    d[x][y] := w;
    // Poprzednikiem y jest x
    p[x][y] := x;
  end;
  // Wywołujemy funkcję
  // Floyda-Warshalla
  writeln;
  if FloydWarshall then
  begin
    // Wyświetlamy wyniki
    for i := 0 to n-1 do
      for j := 0 to n-1 do
      begin
        write(i, '-', j, ' : ');
        FWPath(i, j);
        if d[i][j] < MAXINT then
          write('$', d[i][j]);
        writeln;
      end;
  end
  else
    writeln('Negative cycle found');
  writeln;
  // Usuwamy macierze dynamiczne
  for i := 0 to n-1 do
  begin
    SetLength(d[i], 0);
    SetLength(p[i], 0);
  end;
  SetLength(d, 0);
  SetLength(p, 0);
end.
C++
// Algorytm Floyda-Warshalla
// Data: 21.04.2014
// (C)2014 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>

using namespace std;

// "plus nieskończoność"
const int MAXINT = 2147483647;

// Zmienne globalne
//-----------------
// Macierze kosztów
// oraz poprzedników
int **d, **p;
// Liczba wierzchołków
// i krawędzi
int n, m;

// Funkcja wyznaczania
// kosztów dojścia oraz
// minimalnych ścieżek
// w grafie ważonym
//---------------------
bool FloydWarshall()
{
  int i, j, k, w;

  for(k = 0; k < n; k++)
    for(i = 0; i < n; i++)
      for(j = 0; j < n; j++)
      {
        if((d[i][k] == MAXINT) ||
           (d[k][j] == MAXINT))
          continue;
        w = d[i][k]+d[k][j];
        if(d[i][j] > w)
        {
          d[i][j] = w;
          p[i][j] = p[k][j];
        }
      }
  for(i = 0; i < n; i++)
    if(d[i][i] < 0) return
      // Ujemny cykl
      false;
  return true;
}

// Rekurencyjna procedura
// odtwarzania minimalnej
// ścieżki z macierzy
// poprzedników p
//-----------------------
void FWPath(int i, int j)
{
  if(i == j)
    cout << i << " ";
  else if(p[i][j] == -1)
    cout << "NO PATH";
  else
  {
    FWPath (i, p [i][j]);
    cout << j << " ";
  }
}

// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
int main()
{
  int i, j, x, y, w;

  // Czytamy liczbę
  // wierzchołków oraz
  // krawędzi
  cin >> n >> m;
  // Tworzymy dynamiczną
  // macierz d
  d = new int * [n];
  // Tworzymy dynamiczną
  // macierz p
  p = new int * [n];

  for(i = 0; i < n; i++)
  {
    // Tworzymy wiersz
    // macierzy d
    d[i] = new int [n];
    // Tworzymy wiersz
    // macierzy p
    p[i] = new int [n];
    for(j = 0; j < n; j++)
    {
      // Wiersz d wypełniamy
      // największą liczbą
      // dodatnią
      d[i][j] = MAXINT;
      // Wiersz p wypełniamy
      // liczbami -1
      // (brak poprzednika)
      p[i][j] = -1;
    }
    // Jednakże na przekątnej d
    // wpisujemy 0
    d[i][i] = 0;
  }
  for(i = 0; i < m; i++)
  {
    // Czytamy definicję krawędzi
    cin >> x >> y >> w;
    // Wagę krawędzi umieszczamy
    // w macierzy d
    d[x][y] = w;
    // Poprzednikiem y jest x
    p[x][y] = x;
  }
  // Wywołujemy procedurę
  // Floyda-Warshalla
  cout << endl;
  if(FloydWarshall())
  {
    // Wyświetlamy wyniki
    for(i = 0; i < n; i++)
      for(j = 0; j < n; j++)
      {
        cout << i << "-"
             << j << ": ";
        FWPath(i, j);
        if(d[i][j] < MAXINT)
          cout << "$" << d[i][j];
        cout << endl;
      }
  }
  else
    cout << "Negative cycle found"
         << endl;
  cout << endl;
  // Usuwamy macierze dynamiczne
  for(i = 0; i < n; i++)
  {
    delete [] d[i];
    delete [] p[i];
  }
  delete [] d;
  delete [] p;
  return 0;
}
Basic
' Algorytm Floyda-Warshalla
' Data: 21.04.2014
' (C)2014 mgr Jerzy Wałaszek
'---------------------------

' "plus nieskończoność"
const MAXINT = 2147483647

' Zmienne globalne
'-----------------
' Macierze kosztów oraz poprzedników
Dim Shared As Integer Ptr Ptr d, p
' Liczba wierzchołków i krawędzi
Dim Shared As Integer n, m

' Funkcja wyznaczania
' kosztów dojścia oraz
' minimalnych ścieżek
' w grafie ważonym
'---------------------
Function FloydWarshall As Integer
  Dim As Integer i, j, k, w
  For k = 0 To n-1
    For i = 0 To n-1
      For j = 0 To n-1
        if (d[i][k] = MAXINT) OrElse _
           (d[k][j] = MAXINT) Then _
          Continue For
        w = d[i][k]+d[k][j]
        If d[i][j] > w Then
          d[i][j] = w
          p[i][j] = p[k][j]
        End If
      Next
    Next
  Next
  For i = 0 To n-1
    If d[i][i] < 0 Then
      ' Ujemny cykl
      Return 0
    End If
  Next
  Return 1
End Function

' Rekurencyjna procedura
' odtwarzania minimalnej
' ścieżki z macierzy
' poprzedników p
'----------------------
Sub FWPath(ByVal i As Integer, _
           ByVal j As Integer)
  If i = j Then
  	 Print i;
  ElseIf p[i][j] = -1 Then
    Print " NO PATH";
  Else
    FWPath(i, p[i][j])
    Print j;
  End If
End Sub

' **********************
' *** PROGRAM GŁÓWNY ***
' **********************

Dim As Integer i, j, x, y, w

Open Cons For Input As #1
' Czytamy liczbę wierzchołków
' oraz krawędzi
Input #1, n, m
' Tworzymy dynamiczną
' macierz d
d = New Integer Ptr [n]
' Tworzymy dynamiczną
' macierz p
p = New Integer Ptr [n]
For i = 0 To n-1
  ' Tworzymy wiersz
  ' macierzy d
  d[i] = New Integer [n]
  ' Tworzymy wiersz
  ' macierzy p
  p[i] = New Integer [n]
  For j = 0 To n-1
    ' Wiersz d wypełniamy
    ' największą liczbą
    ' dodatnią
    d[i][j] = MAXINT
    ' Wiersz p wypełniamy
    ' liczbami -1
    ' (brak poprzednika)
    p[i][j] = -1
  Next
  d[i][i] = 0
Next
For i = 1 To m
  ' Czytamy definicję krawędzi
  Input #1, x, y, w
  ' Wagę krawędzi umieszczamy
  ' w macierzy d
  d[x][y] = w
  ' Poprzednikiem y jest x
  p[x][y] = x
Next
' Wywołujemy funkcję
' Floyda-Warshalla
Print
If FloydWarshall() = 1 Then
  ' Wyświetlamy wyniki
  For i = 0 To n-1
    For j = 0 To n-1
      Print Using "&-&:";i;j;
      FWPath(i, j)
      If d[i][j] < MAXINT Then _
        Print Using " $&";d[i][j];
      Print
    Next
  Next
Else
  Print "Negative cycle found"
End If
Print
' Usuwamy macierze dynamiczne
for i = 0 To n-1
  Delete [] d[i]
  Delete [] p[i]
Next
Delete [] d
Delete [] p
End
Python (dodatek)
# Algorytm Floyda-Warshalla
# Data: 19.02.2025
# (C)2014 mgr Jerzy Wałaszek
#---------------------------

# "plus nieskończoność"
MAXINT = 2147483647

# Funkcja wyznaczania
# kosztów dojścia oraz
# minimalnych ścieżek
# w grafie ważonym
#---------------------
def floyd_warshall():
    global n,d,p
    for k in range(n):
        for i in range(n):
            for j in range(n):
                if (d[i][k] == MAXINT) or \
                     (d[k][j] == MAXINT):
                    continue
                w = d[i][k]+d[k][j]
                if d[i][j] > w:
                    d[i][j] = w
                    p[i][j] = p[k][j]
    for i in range(n):
        if d[i][i] < 0:
            # Ujemny cykl
            return False
    return True


# Rekurencyjna procedura
# odtwarzania minimalnej
# ścieżki z macierzy
# poprzedników p
#----------------------
def fw_path(i, j):
    global p
    if i == j:
        print(i, end=" ")
    elif p[i][j] == -1:
        print(" NO PATH", end=" ")
    else:
        fw_path(i, p[i][j])
        print(j, end=" ")


# **********************
# *** PROGRAM GŁÓWNY ***
# **********************

# Czytamy liczbę wierzchołków
# oraz krawędzi
z = input().split()
n = int(z[0])
m = int(z[1])
# Tworzymy dynamiczną
# macierz d
d = [None] * n
# Tworzymy dynamiczną
# macierz p
p = [None] * n
for i in range(n):
    # Tworzymy wiersz
    # macierzy d
    d[i] = [MAXINT] * n
    # Tworzymy wiersz
    # macierzy p
    p[i] = [-1] * n
    d[i][i] = 0
for i in range(m):
    # Czytamy definicję krawędzi
    z = input().split()
    x = int(z[0])
    y = int(z[1])
    w = int(z[2])
    # Wagę krawędzi umieszczamy
    # w macierzy d
    d[x][y] = w
    # Poprzednikiem y jest x
    p[x][y] = x
# Wywołujemy funkcję
# Floyda-Warshalla
print()
if floyd_warshall():
    # Wyświetlamy wyniki
    for i in range(n):
        for j in range(n):
            print(i,"-",j,sep="",end=" ")
            fw_path(i, j)
            if d[i][j] < MAXINT:
                print(" $",d[i][j],sep="",end=" ")
            print()
else:
    print("Negative cycle found")
print()
# Usuwamy macierze dynamiczne
for i in range(n):
    d[i] = None
    p[i] = None
del d,p
Wynik:
5 13
0 1 5
0 2 4
0 3 8
1 0 -4
1 2 -2
1 4 5
2 3 5
2 4 2
3 0 -1
3 1 2
3 4 -1
4 2 4
4 3 2

0-0 : 0 $0
0-1 : 0 1 $5
0-2 : 0 1 2 $3
0-3 : 0 1 2 4 3 $7
0-4 : 0 1 2 4 $5
1-0 : 1 0 $-4
1-1 : 1 $0
1-2 : 1 2 $-2
1-3 : 1 2 4 3 $2
1-4 : 1 2 4 $0
2-0 : 2 4 3 1 0 $2
2-1 : 2 4 3 1 $6
2-2 : 2 $0
2-3 : 2 4 3 $4
2-4 : 2 4 $2
3-0 : 3 1 0 $-2
3-1 : 3 1 $2
3-2 : 3 1 2 $0
3-3 : 3 $0
3-4 : 3 4 $-1
4-0 : 4 3 1 0 $0
4-1 : 4 3 1 $4
4-2 : 4 3 1 2 $2
4-3 : 4 3 $2
4-4 : 4 $0

do podrozdziału  do strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2026 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.