Ein *Graph* ist eine Menge von *Vertizes* zusammen mit einer Menge von *Kanten*. Jede Kante verbindet zwei Vertizes, und zwischen zwei gegebenen Vertizes existiert maximal eine Kante.
$w(i, j)$ ist Länge der Kante von Vertex $i$ nach Vertex $j$. Der Einfachheit halber werden die Vertizes mit $0, 1, \ldots, n-1$ numeriert.
Der Algorithmus berechnet Schrittweise die Funktion $s(i, j, k)$ für alle $i$ und $j$. Dabei ist $s(i, j, k)$ der kürzeste Weg von $i$ nach $j$, der nur Vertizes ${1, \ldots, k}$ als Zwischen-Vertex verwendet. Der Algorithmus erhöht iterativ die Anzahl der zugelassenen Zwischen-Vertizes, bis der ganze Graph abgedeckt ist:
1. Wenn man keine anderen Vertizes benutzen darf, dann ist der direkte Weg der Kürzeste.
$$s(i, j, 0) = w(i, j)$$
2. Wenn ein weiterer Vertex zugelassen wird, dann ist der kürzeste Weg entweder
- der bisher gefundene Weg, oder
- der bisherige kürzeste Weg vom Startpunkt zum neuen Punkt, gefolgt vom bisherigen kürzesten Weg vom neuen Punkt zum Endpunkt.
-- Functor macht einige Definitionen unten einfacher
instanceFunctorWeightwhere
fmapf(Weighti)=Weight$fi
fmapfInfinity=Infinity
instanceNuma=>Num(Weighta)where
Weighti+Weightj=Weight$i+j
_+_=Infinity
Weighti*Weightj=Weight$i*j
_*_=Infinity
fromInteger=Weight.fromInteger
negate=fmapnegate
abs=fmapabs
signum=fmapsignum
```
%% Cell type:markdown id: tags:
`(*)`, `abs` und `signum` werden nicht benötigt, sollte aber trotzdem deklariert werden. Eine andere Möglichkeit wäre, sie als `undefined` zu deklarieren.
`negate` ist mathematisch nicht ganz sauber, da
```haskell
negateInfinity==Infinity
```
reicht für unsere Zwecke aber aus.
Der Algorithmus funktioniert auch für gerichtete Kanten und sogar für negative Kanten-Gewichte, solange es keine *negativen Zyklen* gibt.