Tilbake
4.3

4.3 Korteste vei fra én kilde — Dijkstra, Bellman-Ford, DAG

`Dijkstra`, `Bellman-Ford` og `DAG-Shortest-Path` — krav per algoritme (negative kanter/sykler), kjøretider og forgjengerstrukturen.

60 min
7 oppgaver
Korteste vei fra én kildeDijkstraBellman-FordDAG
Din fremgang i kapitlet
0 / 7 oppgaver

Forkunnskaper

- kap. 4.1 — grafrepresentasjon og traversering. Du bør
vite hva en naboliste er, og at BFS finner veien med færrest kanter
ikke den med minst vekt. Forskjellen er hele grunnen til at dette kapitlet
finnes.
- kap. 4.1 dekker også topologisk sortering, som
DAG-Shortest-Path bygger direkte på.
- kap. 3.1 — hauger. Dijkstra bruker en prioritetskø,
og kjøretiden O(ElgV)O(E\lg V) er nettopp prisen for at prioritetskøen er en
binærhaug.
- kap. 1.1 — asymptotisk notasjon. Her skiller vi bevisst
mellom Θ\Theta (grensen er tett) og OO (bare øvre grense er vist).

Er logaritmen i lgV\lg V rusten, er Potenser og logaritmer et raskt
oppfriskningskapittel; lgn\lg n betyr alltid log2n\log_2 n i denne boka. Trenger du
et mykere første møte med selve OO-notasjonen, ligger det i
Algoritmedefinisjon, pseudokode og kompleksitet (Big-O).

Notasjons- og pseudokodeliste

Kantslakking — motoren i alle tre algoritmene (~12 min)

Tenk på en bilist som planlegger ruta si over et vegnett med bomstasjoner.
Hun har et ark med et anslag for hver by: «hit kommer jeg for høyst så mange
kroner». Anslagene starter håpløst dårlige — alle er «uendelig», bortsett fra
byen hun står i, som koster 0. Så går hun gjennom vegstrekningene én for én, og
hver gang hun ser at en strekning gir en billigere måte å nå en by på, retter hun
anslaget ned.

Det er nøyaktig det algoritmene i dette kapitlet gjør. Anslaget kalles d[v]d[v], og
operasjonen som retter det ned, kalles slakking. Alle tre algoritmene er den
samme operasjonen, kjørt i tre forskjellige rekkefølger.

Underveis noterer hun også hvor hun kom fra: hvis den billigste måten å nå vv
går via uu, skriver hun π[v]=u\pi[v] = u. Til slutt kan hun følge disse notatene
bakover fra en hvilken som helst by og lese ut hele ruta. Det er derfor svaret på
en korteste-vei-oppgave nesten alltid er to ting: tallene (dd) og veien
(π\pi).

Korteste vei fra én kilde

Problemet med å finne den billigste veien fra én bestemt startnode til
alle de andre nodene i en vektet graf, ikke bare til én bestemt målnode.

Vekten til en vei er summen av vektene på kantene i den. Det engelske navnet er
single-source shortest paths, ofte forkortet SSSP. At problemet gjelder alle
mål samtidig, er ikke sløsing: enhver kjent algoritme som finner den billigste
veien til ett mål, finner underveis også veien til alle nodene som er
nærmere. Å be om mindre gjør ikke jobben raskere.

Løses av Dijkstra i O(ElgV)O(E\lg V) når alle kantvekter er ikke-negative, av
Bellman-Ford i Θ(VE)\Theta(VE) ellers, og av DAG-Shortest-Path i Θ(V+E)\Theta(V+E)
når grafen er syklusfri.

Kantslakking (*relax*)

Å prøve om kanten fra uu til vv gir en billigere vei til vv enn den vi
allerede har funnet — og i så fall rette ned anslaget.

Testen er d[v] > d[u] + w(u,v). Er den sann, settes d[v] = d[u] + w(u,v) og
pi[v] = u. Er den usann, skjer ingenting. Merk den strenge ulikheten: er de
to like store, gjør vi ingen endring, og forgjengeren står som den står.

Kjøretid Θ(1)\Theta(1) per kant. Slakking gjør aldri d[v]d[v] større, og den kan
aldri gjøre d[v]d[v] mindre enn den sanne korteste veien δ(s,v)\delta(s,v) — det følger
av trekantulikheten.

d[v]d[v] — korteste-vei-estimatet

Det beste tallet algoritmen har funnet så langt for veien fra kilden til vv.

Det starter på \infty for alle noder unntatt kilden, som starter på 0, og det
går bare nedover underveis. Når algoritmen er ferdig, er d[v]d[v] lik den sanne
korteste veien δ(s,v)\delta(s,v) — og hvis vv ikke er nåbar fra kilden, står d[v]d[v]
igjen på \infty.

Dette er størrelsen eksamen ber om når den sier «oppgi v.d for hver node».

π[v]\pi[v] — forgjengeren

Noden algoritmen kom fra da den sist forbedret d[v]d[v].

Den starter på NIL for alle noder og oppdateres hver gang en slakking lykkes.
Følger du π\pi bakover fra vv, får du hele veien fra kilden til vv — i motsatt
rekkefølge. Kantene (π[v],v)(\pi[v], v) danner til sammen et tre med kilden som rot.

Kjøretid Θ(1)\Theta(1) å oppdatere. Fella er å tro at π\pi peker framover: den
peker alltid mot kilden, aldri mot målet.

✏️Eksempel 1: Én slakking, og én som ikke gjør noe

Node u har d[u] = 5. Kanten fra u til v har vekt 3.

a) v har d[v] = 11 og pi[v] = NIL. Utfør Relax(u, v, w).

b) En annen node v har d[v] = 7 og pi[v] = x. Utfør Relax(u, v, w)
med den samme kanten på 3.

a) Sporingen:

StørrelseFør slakkingenTestEtter slakkingen
d[u]5uendret5
d[v]1111 er større enn 5 + 3 = 88
pi[v]NILforgjengeren settes til uu

Sluttilstand: d[v] = 8, pi[v] = u
b) Sporingen:
StørrelseFør slakkingenTestEtter slakkingen
d[u]5uendret5
d[v]77 er ikke større enn 5 + 3 = 87
pi[v]xingen endringx

Sluttilstand: d[v] = 7, pi[v] = x — uendret.

Poenget med b) er at 7=5+317 = 5 + 3 - 1 ikke er større enn 8, så testen slår ikke

til. Hadde d[v] vært nøyaktig 8, hadde den heller ikke slått til: ulikheten er

streng. Det høres ut som en detalj, men det er den vanligste kilden til at to
studenter får ulik π\pi-struktur på det samme eksempeloppgavesettet.

📝Oppgave 1

(Innstegsoppgave, sjanger C — håndkjøring, altså at du utfører operasjonen steg
for steg og oppgir bare sluttilstanden.) Tre noder har d[u] = 4, d[v] = 12 og
d[x] = 20, og pi[u] = s mens pi[v] og pi[x] er NIL. Utfør disse tre
slakkingene i rekkefølge:

a) Relax(u, v, w) med w(u,v) = 5
b) Relax(u, x, w) med w(u,x) = 9
c) Relax(v, x, w) med w(v,x) = 3

Oppgi d og pi for alle tre nodene til slutt. Oppgaven ber om verdiene, ikke
om en forklaring av hva slakking er.

Dijkstra — den grådige, og kravet den stiller (~15 min)

Tilbake til bilisten. Den smarteste måten å jobbe seg gjennom kartet på, er å ta
byene i rekkefølge etter hvor billige de er: den nærmeste først, så den nest
nærmeste, og så videre. Når hun har funnet den aller billigste byen som ennå ikke
er behandlet, kan hun låse anslaget for den — ingen senere oppdagelse kan
gjøre den billigere.

Det er Dijkstra. Algoritmen holder alle ubehandlede noder i en prioritetskø
sortert på dd, plukker ut den minste med Extract-Min, låser den, og slakker
alle kantene ut fra den. Så gjentar den til køen er tom.

Men se på argumentet for låsingen én gang til: «ingen senere oppdagelse kan gjøre
den billigere». Det holder bare hvis det å gå en omvei alltid koster mer.
Med en negativ kantvekt kan en omvei koste mindre — og da faller hele resonnementet.
Det er derfor Dijkstra krever ikke-negative kantvekter, og det er den viktigste
enkeltsetningen i dette kapitlet.

`Dijkstra`

Finner korteste vei fra én kilde ved å plukke den nærmeste ubehandlede noden fra
en prioritetskø og slakke kantene ut fra den, om og om igjen.

Metoden er grådig: hver runde tar den det som ser best ut akkurat nå, og går
aldri tilbake på valget. Når en node er tatt ut av køen, er dd-verdien dens
endelig.

Kjøretid O(ElgV)O(E\lg V) med binærhaug — VV kall på Extract-Min og opptil EE kall
Decrease-Key, hvert på O(lgV)O(\lg V). Krever ikke-negative kantvekter. Med
én eneste negativ kant kan svaret bli galt, og da må du bruke Bellman-Ford.

Prioritetskø

En samling elementer med nøkler, der du alltid kan få ut elementet med minst
nøkkel — uten å sortere hele samlingen først.

I Dijkstra er nøkkelen d[v]d[v], og de to operasjonene som brukes, er
Extract-Min (ta ut den nærmeste ubehandlede noden) og Decrease-Key (senk
nøkkelen når en slakking lyktes).

Implementert som binærhaug koster begge O(lgV)O(\lg V), og det er nettopp derfor
Dijkstra lander på O(ElgV)O(E\lg V) og ikke på noe lineært.

📜Pseudokode-kontrakt: `Dijkstra`
Antagelser om representasjon. Grafen G=(V,E)G=(V,E) er rettet og gitt som
nabolister, slik at kantene ut fra en node kan gjennomløpes i tid proporsjonalt
med antallet. Hver node v har feltene v.d og v.pi. Vektfunksjonen w
oppgir vekten på hver kant. Q er en prioritetskø på v.d, i praksis en
binærhaug.

Prebetingelse: alle kantvekter er ikke-negative, w(u,v) >= 0.
Postbetingelse: for hver node v er v.d lik vekten til en korteste vei fra
s til v, og v.pi peker på forgjengeren på en slik vei. Noder som ikke er
nåbare fra s, står igjen med v.d = uendelig.

Dijkstra(G, w, s)
  Input:  graf G = (V, E) med ikke-negative vekter w, kilde s
  Output: v.d og v.pi for hver node v i V
  Initialize-Single-Source(G, s)
  S = tom mengde
  Q = alle noder i V, med noekkel v.d
  while Q er ikke tom
      u = Extract-Min(Q)
      legg u til S
      for hver kant (u, v) ut fra u
          Relax(u, v, w)

Initialize-Single-Source(G, s)
  for hver node v i V
      v.d = uendelig
      v.pi = NIL
  s.d = 0

Relax(u, v, w)
  if v.d > u.d + w(u, v)
      v.d = u.d + w(u, v)
      v.pi = u

Grunnideen i én setning: når en node tas ut av Q, er den den nærmeste av
alle som gjenstår, og siden ingen kant kan trekke fra noe underveis, finnes det
ingen vei rundt som kan bli billigere — altså er u.d endelig i det øyeblikket.

Kjøretid: O(ElgV)O(E\lg V). Hver node tas ut av køen nøyaktig én gang, altså VV
kall på Extract-Min à O(lgV)O(\lg V); hver kant slakkes nøyaktig én gang, altså
opptil EE kall på Decrease-Key à O(lgV)O(\lg V). Summen O((V+E)lgV)O((V+E)\lg V) skrives
O(ElgV)O(E\lg V) når grafen er sammenhengende, siden EV1E \ge V-1 da. Merk at det er
OO, ikke Θ\Theta: antallet vellykkede Decrease-Key-kall avhenger av grafen.

✏️Eksempel 2: `Dijkstra` på et bomvegnett

Seks kryss i et vegnett heter S, A, B, C, D og E. Strekningene er
enveiskjørte, og tallet på hver strekning er bomavgiften i kroner:

S -> A  4      B -> A   1      C -> D  2
S -> B  2      B -> C   8      C -> E  6
A -> C  5      B -> D  10      D -> E  3

Kjør Dijkstra fra S. Oppgi v.d for hver node.

Prioritetskøen plukker alltid den ubehandlede noden med minst d. Er to like,
tas den som kommer først alfabetisk.

Sporingstavlen. Hver rad er ett Extract-Min pluss slakkingen av alle kantene
ut fra noden som ble plukket:

StegExtract-Min gird for nodenSlakking av kantene utd etter steget
1S0(S,A): 0 + 4 = 4 < \infty, d[A] = 4, pi[A] = S; (S,B): 0 + 2 = 2 < \infty, d[B] = 2, pi[B] = SS: 0, A: 4, B: 2, C: \infty, D: \infty, E: \infty
2B2(B,A): 2 + 1 = 3 < 4, d[A] = 3, pi[A] = B; (B,C): 2 + 8 = 10 < \infty, d[C] = 10, pi[C] = B; (B,D): 2 + 10 = 12 < \infty, d[D] = 12, pi[D] = BS: 0, A: 3, B: 2, C: 10, D: 12, E: \infty
3A3(A,C): 3 + 5 = 8 < 10, d[C] = 8, pi[C] = AS: 0, A: 3, B: 2, C: 8, D: 12, E: \infty
4C8(C,D): 8 + 2 = 10 < 12, d[D] = 10, pi[D] = C; (C,E): 8 + 6 = 14 < \infty, d[E] = 14, pi[E] = CS: 0, A: 3, B: 2, C: 8, D: 10, E: 14
5D10(D,E): 10 + 3 = 13 < 14, d[E] = 13, pi[E] = DS: 0, A: 3, B: 2, C: 8, D: 10, E: 13
6E13ingen kanter utS: 0, A: 3, B: 2, C: 8, D: 10, E: 13

Nodene ble låst i rekkefølgen S, B, A, C, D, E — altså
stigende etter d, som seg hør og bør for en grådig algoritme.
På eksamen leverer du bare linja under — tavlen er her for å vise hvordan du
kommer dit.

v.d: S: 0, A: 3, B: 2, C: 8, D: 10, E: 13
Forgjengerne, hvis oppgaven også ber om dem: S: NIL, A: B, B: S, C: A, D: C, E: D
Legg merke til steg 2 og 3: A fikk først d = 4 direkte fra S, men ble

senket til 3 da B ble behandlet. Det er lov — A var ikke tatt ut av køen
ennå. Etter at en node ER tatt ut, skjer det aldri mer.

Fellenote. Fellen her er å stoppe før køen er tom, eller å låse A med 4 i
det øyeblikket den fikk sin første verdi. En d-verdi er ikke endelig før noden

er plukket av Extract-Min.

📝Oppgave 2
Eksamensnivå, sjanger E
a) Hva er kjøretiden til Dijkstra når prioritetskøen er en binærhaug?
b) Begrunn den i én setning ved å telle operasjonene på prioritetskøen.
c) Hvorfor skriver vi OO og ikke Θ\Theta her?

Når Dijkstra går galt (~8 min)

— naturlig pausepunkt —

La oss se hva som faktisk skjer med en negativ kant. Et ferjeselskap gir rabatt
på en bestemt overfart hvis du har kjøpt billett på en annen strekning først. I
grafen blir den rabatterte overfarten en kant med negativ vekt: du betaler
mindre samlet enn du gjorde før du tok den.

Nå er antakelsen som Dijkstra hviler på, brutt. Algoritmen låser en node fordi
«ingen omvei kan bli billigere» — men en omvei innom den rabatterte kanten kan
være akkurat det.

✏️Eksempel 3: `Dijkstra` svarer feil på fire noder

Grafen har fire noder og fire kanter:

S -> A   2
S -> B   3
B -> A  -2
A -> C   1

a) Kjør Dijkstra fra S mekanisk, uten å «reparere» noe, og oppgi v.d.
b) Hva er den sanne korteste veien til C?

a) Sporingen, kjørt mekanisk:

StegExtract-Min gird for nodenSlakking av kantene utd etter steget
1S0(S,A): 0 + 2 = 2 < \infty, d[A] = 2, pi[A] = S; (S,B): 0 + 3 = 3 < \infty, d[B] = 3, pi[B] = SS: 0, A: 2, B: 3, C: \infty
2A2(A,C): 2 + 1 = 3 < \infty, d[C] = 3, pi[C] = AS: 0, A: 2, B: 3, C: 3
3B3(B,A): 3 + -2 = 1 < 2, d[A] = 1, pi[A] = BS: 0, A: 1, B: 3, C: 3
4C3ingen kanter utS: 0, A: 1, B: 3, C: 3

Nodene ble låst i rekkefølgen S, A, B, C.
Dijkstra svarer: S: 0, A: 1, B: 3, C: 3
b) Den sanne korteste veien til C går S, B, A, C og koster
3+(2)+1=23 + (-2) + 1 = 2. Kjørt med Bellman-Ford, som tåler negative kanter, blir
fasiten: S: 0, A: 1, B: 3, C: 2

Avviket: Dijkstra svarer d[C] = 3; korrekt korteste vei er 2.

Hvor gikk det galt? I steg 2 ble A tatt ut av køen med d[A] = 2 og låst.

Kanten fra A til C ble slakket med den verdien, så d[C] ble 3. Først i
steg 3 oppdaget algoritmen at A egentlig kunne nås for 1 via B — men da var
A allerede behandlet, og Dijkstra går aldri tilbake til en behandlet node.

Forbedringen av d[A] rakk aldri fram til C.

Merk en viktig nyanse. Dijkstra svarer ikke alltid feil når det finnes en
negativ kant; på mange grafer kommer den heldigvis i mål. Men den gir ingen
garanti, og på eksamen er det garantien som spørres etter. Riktig svar er derfor
alltid: nei, Dijkstra kan ikke brukes — bruk Bellman-Ford.

📝Oppgave 3
Eksamensnivå, sjanger F
a) En rettet graf har 40 kanter. 39 av dem har positiv vekt, én har vekten
1-1. Kan Dijkstra brukes til å finne korteste vei fra en kilde s?
b) Samme graf: kan Bellman-Ford brukes?
c) Stemmer det at Dijkstra alltid gir feil svar når grafen har en negativ
kant?

Bellman-Ford — den robuste (~15 min)

Når du ikke kan stole på rekkefølgen, dropper du rekkefølgen. Bellman-Ford
slakker rett og slett alle kantene i grafen, om og om igjen, V1V-1 ganger.

Hvorfor akkurat V1V-1? Fordi en korteste vei aldri kan ha flere enn V1V-1 kanter
— hadde den hatt flere, ville den besøkt en node to ganger, altså gått i en
sykel, og en sykel med positiv vekt kan alltid klippes bort. Etter runde 1 er
alle korteste veier med én kant funnet, etter runde 2 alle med to kanter, og så
videre.

Og der Dijkstra bare feiler stille på en negativ sykel, gjør Bellman-Ford det
eneste ærlige: den kjører én runde til. Hvis en eneste kant fortsatt kan
slakkes etter V1V-1 runder, finnes det en negativ sykel nåbar fra kilden, og da
returnerer algoritmen USANN. Det er riktig svar, for da finnes det ingen korteste
vei: du kan gå rundt sykelen så mange ganger du vil og få vilkårlig lav vekt.

`Bellman-Ford`

Finner korteste vei fra én kilde ved å slakke samtlige kanter i grafen V1V-1
ganger, i en fast rekkefølge.

Den bryr seg ikke om hvilken rekkefølge kantene står i — svaret blir det samme —
men antall runder som trengs, avhenger av rekkefølgen. Etter de V1V-1 rundene
kjører den en kontrollrunde til: kan noen kant fortsatt slakkes, returnerer den
USANN.

Kjøretid Θ(VE)\Theta(VE). Tåler negative kanter og oppdager negative sykler
som er nåbare fra kilden. Med tidlig stopp — bryt ut når en runde ikke endret
noe — blir beste tilfelle Θ(V+E)\Theta(V+E).

Negativ sykel

En sykel i en rettet graf der summen av kantvektene er mindre enn null.

Er den nåbar fra kilden, finnes det ingen korteste vei til nodene på og bak
sykelen: du kan runde den én gang til og få en billigere «vei», i det uendelige.
Problemet er da udefinert, ikke bare vanskelig.

Bellman-Ford oppdager dette i kontrollrunden etter de V1V-1 slakkerundene og
returnerer USANN. En negativ sykel som ikke er nåbar fra kilden, påvirker
ingenting og oppdages heller ikke.

Tidlig stopp i `Bellman-Ford`

Å bryte ut av løkka så snart en hel runde med slakkinger ikke endret en eneste
dd-verdi.

Da kan ingen senere runde endre noe heller, siden hver runde bare avhenger av
tilstanden ved rundens start. Svaret blir identisk med å kjøre alle V1V-1
rundene.

Dette gir beste tilfelle Θ(V+E)\Theta(V+E) — én runde slakking pluss kontrollen —
mens verste tilfelle fortsatt er Θ(VE)\Theta(VE). Merk at eksamen som regel ber deg
kjøre et oppgitt antall runder; da kjører du nøyaktig så mange, uansett.

📜Pseudokode-kontrakt: `Bellman-Ford`
Antagelser om representasjon. Grafen G=(V,E)G=(V,E) er rettet og gitt som en
kantliste, siden algoritmen uansett skal gjennom alle kanter hver runde.
Rekkefølgen på kantlista er fast og oppgitt. Hver node v har feltene v.d og
v.pi.

Prebetingelse: ingen — vektene kan være negative.
Postbetingelse: hvis ingen negativ sykel er nåbar fra s, returneres SANN,
og v.d er vekten til en korteste vei fra s til v for hver node. Finnes det
en negativ sykel nåbar fra s, returneres USANN, og v.d-verdiene er
meningsløse.

Bellman-Ford(G, w, s)
  Input:  graf G = (V, E) som kantliste, vekter w (kan vaere negative), kilde s
  Output: SANN med v.d og v.pi satt, eller USANN ved negativ sykel naabar fra s
  Initialize-Single-Source(G, s)
  for i = 1 to |V| - 1
      for hver kant (u, v) i E, i den faste rekkefoelgen
          Relax(u, v, w)
  for hver kant (u, v) i E
      if v.d > u.d + w(u, v)
          return USANN
  return SANN

Invarianten i én setning: etter runde ii er v.d korrekt for alle noder
v som har en korteste vei fra s med høyst ii kanter.

Kjøretid: Θ(VE)\Theta(VE). Den ytre for-løkka går V1V-1 ganger, den indre gjennom
alle EE kanter, og hver slakking er Θ(1)\Theta(1); kontrollrunden legger til
Θ(E)\Theta(E), som forsvinner i det største leddet. Her står det Θ\Theta og ikke
OO: uten tidlig stopp gjøres arbeidet uansett hva grafen ser ut som.

✏️Eksempel 4: `Bellman-Ford` på et ferjenett med rabatt

Fem havner heter S, A, B, C og D. Tallene er prisen i hundrelapper for
hver overfart; to av dem er negative fordi selskapet gir rabatt når du allerede
har kjøpt en tidligere billett i kjeden:

S -> A   4      A -> B  -1      C -> D   2
S -> B   6      A -> C   3      D -> A   8
B -> C  -2      B -> D   5

Kantene skal slakkes i denne faste rekkefølgen hver runde:

(D,A), (C,D), (B,D), (B,C), (A,C), (A,B), (S,B), (S,A)

Kjør Bellman-Ford fra S. Oppgi v.d for hver node, og si om algoritmen
returnerer SANN eller USANN.

Grafen har 5 noder, så det kjøres 51=45 - 1 = 4 runder. Sporingstavlen har én rad
per kant per runde:

RundeKantVektTest d[v] > d[u] + w(u,v)?Resultatd etter steget
1(D,A)8d[D] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(C,D)2d[C] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(B,D)5d[B] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(B,C)-2d[B] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(A,C)3d[A] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(A,B)-1d[A] er \inftyingen endringS: 0, A: \infty, B: \infty, C: \infty, D: \infty
1(S,B)60 + 6 = 6 er mindre enn \inftyd[B] = 6, pi[B] = SS: 0, A: \infty, B: 6, C: \infty, D: \infty
1(S,A)40 + 4 = 4 er mindre enn \inftyd[A] = 4, pi[A] = SS: 0, A: 4, B: 6, C: \infty, D: \infty
2(D,A)8d[D] er \inftyingen endringS: 0, A: 4, B: 6, C: \infty, D: \infty
2(C,D)2d[C] er \inftyingen endringS: 0, A: 4, B: 6, C: \infty, D: \infty
2(B,D)56 + 5 = 11 er mindre enn \inftyd[D] = 11, pi[D] = BS: 0, A: 4, B: 6, C: \infty, D: 11
2(B,C)-26 + (-2) = 4 er mindre enn \inftyd[C] = 4, pi[C] = BS: 0, A: 4, B: 6, C: 4, D: 11
2(A,C)34 + 3 = 7 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 6, C: 4, D: 11
2(A,B)-14 + (-1) = 3 er mindre enn 6d[B] = 3, pi[B] = AS: 0, A: 4, B: 3, C: 4, D: 11
2(S,B)60 + 6 = 6 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 4, D: 11
2(S,A)40 + 4 = 4 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 3, C: 4, D: 11
3(D,A)811 + 8 = 19 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 3, C: 4, D: 11
3(C,D)24 + 2 = 6 er mindre enn 11d[D] = 6, pi[D] = CS: 0, A: 4, B: 3, C: 4, D: 6
3(B,D)53 + 5 = 8 er ikke mindre enn 6ingen endringS: 0, A: 4, B: 3, C: 4, D: 6
3(B,C)-23 + (-2) = 1 er mindre enn 4d[C] = 1, pi[C] = BS: 0, A: 4, B: 3, C: 1, D: 6
3(A,C)34 + 3 = 7 er ikke mindre enn 1ingen endringS: 0, A: 4, B: 3, C: 1, D: 6
3(A,B)-14 + (-1) = 3 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 1, D: 6
3(S,B)60 + 6 = 6 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 1, D: 6
3(S,A)40 + 4 = 4 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 3, C: 1, D: 6
4(D,A)86 + 8 = 14 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 3, C: 1, D: 6
4(C,D)21 + 2 = 3 er mindre enn 6d[D] = 3, pi[D] = CS: 0, A: 4, B: 3, C: 1, D: 3
4(B,D)53 + 5 = 8 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 1, D: 3
4(B,C)-23 + (-2) = 1 er ikke mindre enn 1ingen endringS: 0, A: 4, B: 3, C: 1, D: 3
4(A,C)34 + 3 = 7 er ikke mindre enn 1ingen endringS: 0, A: 4, B: 3, C: 1, D: 3
4(A,B)-14 + (-1) = 3 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 1, D: 3
4(S,B)60 + 6 = 6 er ikke mindre enn 3ingen endringS: 0, A: 4, B: 3, C: 1, D: 3
4(S,A)40 + 4 = 4 er ikke mindre enn 4ingen endringS: 0, A: 4, B: 3, C: 1, D: 3

Antall vellykkede slakkinger per runde: runde 1: 2 endringer, runde 2: 3 endringer, runde 3: 2 endringer, runde 4: 1 endringer. Legg
merke til at det skjedde en endring helt til og med runde 4 — den ugunstige
kantrekkefølgen gjør at forbedringene forplanter seg bare ett hakk per runde.
Hadde kantene ligget i motsatt rekkefølge, hadde alt vært på plass etter runde 1.
Kontrollrunden: ingen kant kan slakkes mer, altså ingen negativ sykel nåbar fra S Algoritmen returnerer SANN.
På eksamen leverer du bare linja under — tavlen er her for å vise hvordan du
kommer dit.

v.d: S: 0, A: 4, B: 3, C: 1, D: 3
Forgjengerne: S: NIL, A: S, B: A, C: B, D: C
Fellenote. Fellen her er å stoppe etter runde 1 fordi «det ser ferdig ut».
Det gjorde det ikke: D gikk fra 11 via 6 til 3 gjennom rundene 2, 3 og 4.
Oppgaven ber om verdiene etter at algoritmen er ferdig, ikke etter første runde.

📝Oppgave 4
Eksamensnivå, sjanger C

En rettet graf har nodene S, A, B
og C og kantene

A -> C   2
C -> B  -4
S -> A   6
S -> B   7
B -> A   3

Kantene slakkes i nøyaktig den rekkefølgen de står i lista over, i hver runde.
Kjør Bellman-Ford fra S.

a) Hva er d for hver node etter runde 1?
b) Hva er d for hver node når algoritmen er ferdig?
c) Returnerer algoritmen SANN eller USANN?

Oppgaven ber om verdiene, ikke om en forklaring av algoritmen.

📝Oppgave 5
Eksamensnivå, sjanger C…

En rettet graf har nodene S, X,
Y og Z og kantene

S -> X   4
X -> Y   3
Y -> Z  -2
Z -> X  -3
X -> Z   9

Kantene slakkes i den rekkefølgen de står, i hver runde.

a) Kjør Bellman-Ford fra S og oppgi hvilken kant som fortsatt kan slakkes
i kontrollrunden.
b) Hva returnerer algoritmen, og hva betyr det for spørsmålet «hva er
korteste vei fra S til Z

DAG-Shortest-Path — den raske når grafen er syklusfri (~10 min)

— naturlig pausepunkt —

Et monteringsverksted setter sammen et produkt i en fast rekkefølge: kabinettet
må stå før kortet kan settes inn, kortet før lokket kan skrus på. Noen
delmontasjer kan gjøres i parallell, men ingen operasjon kan komme etter seg
selv. En slik graf har ingen sykler — den er en rettet asyklisk graf, på
engelsk directed acyclic graph, forkortet DAG.

I en DAG kan du sortere nodene i en lineær topologisk orden, der hver kant
peker framover. Og da trenger du verken prioritetskø eller gjentatte runder: gå
gjennom nodene i topologisk orden og slakk kantene ut fra hver av dem, én gang.
Når du kommer til en node, er alle veiene inn til den allerede ferdigbehandlet.

Det gir Θ(V+E)\Theta(V+E) — raskere enn både Dijkstra og Bellman-Ford — og
algoritmen tåler negative kantvekter uten videre, siden det uansett ikke finnes
noen sykel å gå rundt.

Rettet asyklisk graf (DAG)

En rettet graf uten sykler: det finnes ingen vei som starter og ender i den samme
noden.

Navnet kommer fra engelsk, directed acyclic graph. Modellen passer på alt som
har en «må gjøres før»-struktur: monteringsrekkefølger, emneforløp, oppgaver med
avhengigheter.

Nøkkelegenskapen er at nodene kan legges i en topologisk orden. Har grafen bare
én eneste sykel, finnes ingen slik orden, og DAG-Shortest-Path kan ikke
brukes.

Topologisk orden

En rekkefølge på nodene i en rettet asyklisk graf der hver kant peker framover:
går det en kant fra uu til vv, står uu før vv.

Den finnes hvis og bare hvis grafen er asyklisk, og den er sjelden entydig — de
fleste DAG-er har flere gyldige ordener.

Den finnes i Θ(V+E)\Theta(V+E) med en dybde-først-traversering, ved å sortere nodene
etter synkende finish-tid. DAG-Shortest-Path bruker den som sin
behandlingsrekkefølge.

`DAG-Shortest-Path`

Finner korteste vei fra én kilde i en rettet asyklisk graf ved å gå gjennom
nodene i topologisk orden og slakke kantene ut fra hver node nøyaktig én gang.

Grunnen til at én runde holder: når du kommer til en node i topologisk orden, har
alle kantene inn til den allerede vært slakket, så dd-verdien er ferdig.

Kjøretid Θ(V+E)\Theta(V+E) — det er den raskeste av de tre. Krever DAG, men
tåler negative kantvekter helt greit, siden en negativ sykel er umulig i en
syklusfri graf.

📜Pseudokode-kontrakt: `DAG-Shortest-Path`
Antagelser om representasjon. Grafen G=(V,E)G=(V,E) er rettet, asyklisk og
gitt som nabolister. Hver node v har feltene v.d og v.pi. Vektene kan være
negative.

Prebetingelse: G har ingen sykler. Postbetingelse: v.d er vekten til
en korteste vei fra s til v for hver node v, og v.pi gir veien bakover.
Noder som ikke er nåbare fra s, står igjen med v.d = uendelig.

DAG-Shortest-Path(G, w, s)
  Input:  rettet asyklisk graf G = (V, E), vekter w, kilde s
  Output: v.d og v.pi for hver node v i V
  sorter nodene i V topologisk
  Initialize-Single-Source(G, s)
  for hver node u i V, i topologisk orden
      for hver kant (u, v) ut fra u
          Relax(u, v, w)

Invarianten i én setning: når den ytre for-løkka kommer til node u, er
u.d allerede ferdig, fordi hver kant inn til u går fra en node som står
tidligere i den topologiske ordenen og derfor allerede er behandlet.

Kjøretid: Θ(V+E)\Theta(V+E). Den topologiske sorteringen er Θ(V+E)\Theta(V+E),
initialiseringen Θ(V)\Theta(V), og den doble løkka ser på hver kant nøyaktig én
gang, altså Θ(E)\Theta(E). Her er Θ\Theta riktig: arbeidet gjøres uansett hvordan
DAG-en ser ut.

✏️Eksempel 5: `DAG-Shortest-Path` på en monteringslinje

Seks operasjoner heter A til F. En kant fra X til Y betyr at X
gjøres før Y, og vekten er omstillingstiden i minutter — negativ der to
operasjoner deler samme oppsett og verkstedet sparer tid:

A -> B   5      C -> D   7      D -> F   2
A -> C   3      C -> E   4      E -> F  -1
B -> C  -2      D -> E   1

En topologisk orden er A, B, C, D, E, F. Kjør DAG-Shortest-Path fra
A og oppgi v.d for hver node.

Sporingen, én rad per node i topologisk orden:

StegNode i topologisk ordend for nodenSlakking av kantene utd etter steget
1A0(A,B): 0 + 5 = 5 < \infty, d[B] = 5, pi[B] = A; (A,C): 0 + 3 = 3 < \infty, d[C] = 3, pi[C] = AA: 0, B: 5, C: 3, D: \infty, E: \infty, F: \infty
2B5(B,C): 5 + (-2) = 3 ikke mindre enn 3, ingen endring; (B,D): 5 + 6 = 11 < \infty, d[D] = 11, pi[D] = BA: 0, B: 5, C: 3, D: 11, E: \infty, F: \infty
3C3(C,D): 3 + 7 = 10 < 11, d[D] = 10, pi[D] = C; (C,E): 3 + 4 = 7 < \infty, d[E] = 7, pi[E] = CA: 0, B: 5, C: 3, D: 10, E: 7, F: \infty
4D10(D,E): 10 + 1 = 11 ikke mindre enn 7, ingen endring; (D,F): 10 + 2 = 12 < \infty, d[F] = 12, pi[F] = DA: 0, B: 5, C: 3, D: 10, E: 7, F: 12
5E7(E,F): 7 + (-1) = 6 < 12, d[F] = 6, pi[F] = EA: 0, B: 5, C: 3, D: 10, E: 7, F: 6
6F6ingen kanter utA: 0, B: 5, C: 3, D: 10, E: 7, F: 6

På eksamen leverer du bare linja under — tavlen er her for å vise hvordan du
kommer dit.

v.d: A: 0, B: 5, C: 3, D: 10, E: 7, F: 6
Forgjengerne: A: NIL, B: A, C: A, D: C, E: C, F: E
To ting er verdt å legge merke til. I steg 2 ble kanten fra B til C slakket
uten at noe skjedde: 5+(2)=35 + (-2) = 3, og d[C] var allerede 3. Ulikheten er
streng, så pi[C] ble stående på A. Og i steg 5 senket den negative kanten

d[F] fra 12 til 6 — helt uproblematisk, fordi grafen ikke har noen sykel å gå
rundt.

Fellenote. Fellen her er å behandle nodene i alfabetisk rekkefølge i stedet

for topologisk. Med denne grafen ville det gitt samme svar tilfeldigvis, men det

gjør det ikke generelt: hele garantien hviler på at ingen kant peker bakover.

📝Oppgave 6
Eksamensnivå, sjanger C

En rettet asyklisk graf har nodene S,
P, Q, R og T, og kantene

S -> P   3      P -> R   6      Q -> T   9
S -> Q   8      Q -> R   1      R -> T   2
P -> Q  -2

En topologisk orden er S, P, Q, R, T. Kjør DAG-Shortest-Path fra S
og oppgi v.d for hver node.

📝Oppgave 7
Eksamensnivå, sjanger F…

For hver av de fire situasjonene: si
hvilken av Dijkstra, Bellman-Ford og DAG-Shortest-Path du ville brukt, og
oppgi kjøretiden til valget ditt. Velg den raskeste algoritmen som faktisk
kan brukes.

a) Et vegnett med bomavgifter. Alle avgifter er positive, grafen har sykler.
b) En monteringsplan der noen omstillinger sparer tid (negative vekter), og
ingen operasjon kan komme etter seg selv.
c) Et rutenett der to strekninger gir rabatt (negative vekter) og det finnes
sykler.
d) Samme graf som i c), men du skal i tillegg avgjøre om det i det hele tatt
finnes en korteste vei.

Hvilken algoritme når? (~5 min)

Alle tre løser det samme problemet og bruker den samme slakkeregelen. Det som
skiller dem, er hva de krever av grafen — og prisen du betaler for robustheten.

AlgoritmeBeste tilfelleVerste tilfelleKrav og egenskap
Dijkstra (binærhaug)Ω(E+VlgV)\Omega(E + V\lg V)O(ElgV)O(E\lg V)krever ikke-negative kantvekter; grådig, låser én node per runde
Bellman-FordΘ(V+E)\Theta(V+E) med tidlig stoppΘ(VE)\Theta(VE)tåler negative kanter; oppdager negative sykler nåbare fra kilden
DAG-Shortest-PathΘ(V+E)\Theta(V+E)Θ(V+E)\Theta(V+E)krever DAG; tåler negative vekter, raskest av de tre
BFS (til sammenligning)Θ(V+E)\Theta(V+E)Θ(V+E)\Theta(V+E)gir færrest kanter, ikke minst vekt — bare riktig når alle vekter er like

Les tabellen nedenfra og opp når du skal velge: er grafen syklusfri, ta den
øverste raden du har lov til. Er den ikke det, avgjør fortegnene på vektene.
Én ting til som gjelder alle tre: er en node ikke nåbar fra kilden, står dd igjen
\infty. Det er et gyldig svar, ikke en feil.

Begrepsbank

Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp har
lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder
kjernestoffet.

Forgjengertreet

Treet du får ved å tegne inn kanten (π[v],v)(\pi[v], v) for hver node vv som har en
forgjenger.

Det har kilden som rot, og veien fra roten ned til en node er en korteste vei til
den noden. Derfor er π\pi-strukturen svaret når en oppgave spør etter veien
og ikke bare tallet.

Det er ikke nødvendigvis entydig: har grafen to like billige veier til samme
node, avgjør slakkerekkefølgen hvilken av dem som havner i treet.

Trekantulikheten for korteste veier

Regelen om at en korteste vei til vv aldri kan være dyrere enn en korteste vei
til uu pluss kanten fra uu til vv: δ(s,v)δ(s,u)+w(u,v)\delta(s,v) \le \delta(s,u) + w(u,v).

Den er grunnen til at slakking er trygg: operasjonen kan aldri sette d[v]d[v]
lavere enn den sanne korteste veien, for da måtte det finnes en billigere vei enn
den billigste.

Den brukes ikke direkte i håndkjøring, men den er argumentet bak at alle tre
algoritmene i det hele tatt virker.

Vektfunksjonen w(u,v)w(u,v)

Tallet som står på kanten fra uu til vv: kroner i bomavgift, minutter, meter —
det oppgaven sier at det er.

Vekten til en vei er summen av vektene til kantene i den, og det er den summen
korteste-vei-problemet minimerer.

Vær oppmerksom på at «korteste» aldri betyr «færrest kanter» i dette kapitlet.
Det gjør det derimot i BFS, som er det samme som at alle kantvekter er 1.

Nåbar fra kilden

En node vv er nåbar fra kilden ss hvis det finnes minst én rettet vei fra ss
til vv.

Er den ikke nåbar, står d[v]d[v] igjen på \infty når algoritmen er ferdig — og
det er det riktige svaret, ikke et tegn på at du har gjort feil.

Begrepet er også avgjørende for Bellman-Ford: algoritmen oppdager bare de
negative syklene som er nåbare fra kilden. En negativ sykel i en avsondret del av
grafen påvirker ingen av svarene og flagges ikke.

`Extract-Min` og `Decrease-Key`

De to prioritetskø-operasjonene Dijkstra består av: å ta ut noden med minst
dd-verdi, og å senke dd-verdien til en node som ligger i køen.

Extract-Min kalles nøyaktig VV ganger — én gang per node. Decrease-Key
kalles opptil EE ganger, én per vellykket slakking.

Med binærhaug koster begge O(lgV)O(\lg V), og produktet av disse to tellingene er
hele kjøretidsutledningen: O((V+E)lgV)=O(ElgV)O((V+E)\lg V) = O(E\lg V).

Binærhaug som prioritetskø

Den vanlige implementasjonen av prioritetskøen i Dijkstra: et array A[1..n]
tolket som et binærtre, med forelder på indeks i/2\lfloor i/2\rfloor og barna på
2i2i og 2i+12i+1.

I Dijkstra er den en min-haug: forelderen er ikke større enn noen av barna,
slik at den minste dd-verdien alltid ligger på indeks 1.

Både Extract-Min og Decrease-Key koster O(lgV)O(\lg V), fordi begge bare beveger
ett element langs én vei mellom rot og blad. Det er akkurat dette lgV\lg V-leddet
i O(ElgV)O(E\lg V) som er haugen.

Grådig algoritme

En algoritme som i hvert steg tar det valget som ser best ut akkurat der og da,
og aldri går tilbake på det.

Dijkstra er grådig: den plukker den nærmeste ubehandlede noden og låser den for
godt. Det er raskt — men det virker bare når «det som ser best ut nå» faktisk er
best, og det er nettopp det de ikke-negative kantvektene garanterer.

Bellman-Ford er ikke grådig: den revurderer alt, hver runde, og betaler
Θ(VE)\Theta(VE) for å slippe å stole på noen rekkefølge.

Korteste vei som ikke finnes

To ulike tilfeller der spørsmålet «hva er d[v]d[v]?» ikke har et vanlig tall som
svar.

Uendelig: vv er ikke nåbar fra kilden. Da er d[v]=d[v] = \infty, og det er et
gyldig svar du skal skrive ned.

Udefinert: det finnes en negativ sykel på veien til vv. Da finnes det ingen
korteste vei i det hele tatt, og riktig svar er at Bellman-Ford returnerer
USANN — ikke et tall.

Repetisjonsoppgaver

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.

Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Norges teknisk-naturvitenskapelige universitet. Dette er ikke offisielt studiemateriell. Les mer.