4.2 Minimale spenntrær — Prim og Kruskal
`MST-Prim` og `MST-Kruskal`, snittegenskapen og hvorfor en letteste kant over et snitt er **trygg**.
Et fiberselskap skal knytte sammen sju grender. De har kostnadsanslag for hver
mulige trasé, og ett krav: alle grendene skal henge sammen, og totalregningen
skal bli minst mulig. Det er hele problemet dette kapitlet løser — og det løses
av to algoritmer som ser helt ulike ut, men som bygger på nøyaktig samme
prinsipp.
Hvor ofte kommer det? Minimale spenntrær er belagt i 82 % (14 av de 17
settene i grunnlaget). Grunnlaget er de 17 settene fra august 2015 til august
2023 som er gjennomgått tema for tema.
Sjangrene du møter her, med kodene skrevet ut:
- sjanger C — håndkjøring, altså at du utfører algoritmen steg for steg og
oppgir bare sluttilstanden. Her: kjør MST-Kruskal og list kantene i den
rekkefølgen de legges til.
- sjanger D — definisjon med egne ord, altså én presis setning med
hovedpoenget først. Snittegenskapen og ordet trygg er en fast
definisjonsoppgave.
- sjanger F — stemmer dette?, altså ja eller nei først og så én setning.
Den faste fella her er «det minimale spenntreet er entydig» (nei — ikke når
kantvekter er like).
Prioritet: bør sitte. Kruskal-håndkjøring er nesten gratis poeng når du har
gjort den fem ganger, og snittegenskapen er den ene setningen som forklarer
hvorfor både Prim og Kruskal virker.
Slik er kapitlet lagt opp (55 min):
| # | Innhold | Tid |
|---|---|---|
| 1 | Spenntre og minimalt spenntre | ca. 10 min |
| 2 | Snittegenskapen og hva «trygg» betyr | ca. 14 min |
| 3 | MST-Kruskal med Union-Find | ca. 14 min |
| 4 | MST-Prim med prioritetskø | ca. 12 min |
| 5 | Entydighet, kjøretidstabell og repetisjon | ca. 5 min |
Forkunnskaper
- kap. 4.1 — grafer, nabolister og traversering. Her
får kantene i tillegg en vekt, altså et tall som sier hva kanten koster.
- kap. 3.5 — disjunkte mengder, som MST-Kruskal
bruker til å svare på «henger disse to nodene allerede sammen?».
Fra kap. 3.5 trenger du disse tre operasjonene, som
til sammen kalles Union-Find. Dette sto der:
| Operasjon | Hva den gjør | Kjøretid |
|---|---|---|
Make-Set(x) | lager en ny mengde som bare inneholder x; x blir sin egen representant | |
Find-Set(x) | returnerer representanten for mengden x ligger i. To elementer er i samme mengde nøyaktig når Find-Set gir samme svar | nesten konstant |
Union(x, y) | slår sammen mengdene til x og y til én | nesten konstant |
Strukturen er en skog: hver mengde er et tre der hver node peker på
forelderen sin, og roten er representanten.
Find-Set går oppover til roten;Union henger den ene rota under den andre. Med de to standardgrepene — åhenge det lave treet under det høye, og å la
Find-Set peke alle nodene denpasserer rett på rota — blir en følge av operasjoner så nær at vi i
kjøretidsregnskapet under behandler hver operasjon som en konstant.
Slik brukes det i MST-Kruskal: hver node får sin egen mengde medMake-Set. En kant mellom u og v lager en sykel nøyaktig nårFind-Set(u) == Find-Set(v), altså når de allerede henger sammen. Legger vi
kanten til, kaller vi Union(u, v).
- Potenser og logaritmer — hvis i uttrykket
fortsatt kjennes uvant. betyr , altså toerlogaritmen.
Billigst mulig nett som likevel henger sammen (~10 min)
Fiberselskapet har målt opp elleve mulige traseer mellom de sju grendene, med
hver sin gravekostnad. De trenger ikke alle. De trenger akkurat så mange at
signalet kommer fram overalt — og ikke én meter mer enn nødvendig.
Legg merke til at problemet har to krav som trekker mot hverandre. Alt skal
henge sammen, som presser antall traseer opp. Regningen skal være lav, som
presser den ned. Det viser seg at det finnes et eksakt svar på hvor de to
møtes: nettet skal være et tre, og det skal være det letteste treet som
finnes.
Ordet «tre» er ikke tilfeldig. Har du sju grender og bygger åtte traseer, har du
minst én rundtur — og en rundtur betyr at minst én trasé kan fjernes uten at noe
mister forbindelsen. Har du bare fem, faller nettet i to biter. Seks, altså
, er svaret.
Et tre som består av kanter fra grafen selv, og som når alle nodene.
To ting sitter i den setningen. For det første at kantene skal være grafens
egne — du kan ikke oppfinne en trasé som ikke er målt opp. For det andre at
alle nodene skal være med, ikke bare noen. Et spenntre over noder har
nøyaktig kanter og ingen sykel. En graf har et spenntre nøyaktig når den
er sammenhengende; er den delt i to, finnes det ingen.
Et spenntre der summen av kantvektene er minst mulig
(minimum spanning tree, MST).
Vekten skrives , og «minimalt» gjelder denne
summen — ikke antall kanter, som uansett er for alle spenntrær, og ikke
den lengste enkeltkanten. To algoritmer finner et MST i :MST-Kruskal og MST-Prim. Merk formuleringen «et MST»: ved like
kantvekter kan grafen ha flere forskjellige minimale spenntrær, alle med samme
totale vekt.
Fiberselskapets sju grender heter A til G, og de elleve mulige traseene med
kostnad i hundre tusen kroner er:
A-B 4 A-C 2 B-C 5 B-D 10
C-D 3 C-E 8 D-E 6 D-F 11
E-F 7 E-G 9 F-G 1En saksbehandler foreslår disse fem traseene: A–C, C–D, A–B, D–E og E–F.
a) Er forslaget et spenntre?
b) Hva om han i tillegg tar med B–C?
. Følger du kantene, får du A, B, C, D, E og F knyttet sammen, men
G henger utenfor — ingen av de fem kantene rører G. Grenda ville stått uten
fiber.
b) Nei, og nå av motsatt grunn. Med B–C har forslaget seks kanter, altså
riktig antall, men de gale kantene: A–C, C–D, A–B og B–C danner rundturen
A, B, C, A. Da er det ikke et tre, og G er fortsatt ikke med.
Den korte kontrollen du kan gjøre på papiret: tell kantene, og sjekk at
tallet er . Stemmer det ikke, er svaret nei uten mer arbeid. Stemmer det,
må du i tillegg sjekke at alt henger sammen — for kanter er
nødvendig, men ikke tilstrekkelig.
(Innstegsoppgave, sjanger D — definisjon med egne ord, altså én presis setning
med hovedpoenget først.)
a) Hva er et spenntre?
b) Hvor mange kanter har et spenntre i en graf med 12 noder?
c) En graf har 12 noder og 11 kanter, og henger sammen. Hva vet du da om
den?
Snittegenskapen: når er en kant trygg? (~14 min)
Begge MST-algoritmene bygger opp svaret én kant om gangen. Da trenger de en
regel som sier: denne kanten kan du legge til nå, uten fare for at du senere
angrer. Den regelen heter snittegenskapen, og den er kapitlets viktigste
setning.
Tenk deg at du deler grendene i to grupper — hvilke som helst to grupper, så
lenge begge er ikke-tomme og ingen grend er i begge. Den delingen kalles et
snitt. Noen traseer går innad i en gruppe; de bryr vi oss ikke om. Andre går
over delingen, fra den ene gruppen til den andre. Nettet må ha minst én slik
trasé, ellers henger ikke gruppene sammen.
Snittegenskapen sier: den letteste av traseene som krysser, kan du trygt
bygge. Men det gjelder bare hvis snittet er valgt slik at ingen av traseene du
allerede har bestemt deg for, krysser det. Den betingelsen er ikke pynt — uten
den er påstanden gal, og vi viser et konkret moteksempel om litt.
Et snitt er en oppdeling av nodemengden i to deler der begge er
ikke-tomme, ingen node er i begge, og alle noder er i én av dem.
En kant krysser snittet når den ene enden ligger i og den andre i .
Snittet trenger ikke dele grafen i to like store deler — kan godt bestå av
én eneste node. Du velger snittet selv, og i en sammenhengende graf krysser det
alltid minst én kant. Merk at snittet ikke er en operasjon på grafen: ingenting
fjernes, det er bare en måte å dele nodene i to grupper på for å resonnere om
dem.
Et snitt respekterer en kantmengde når ingen kant i
krysser snittet.
Med andre ord: alt du har valgt så langt ligger trygt inne i eller inne i
, ingenting går på tvers. Dette er betingelsen i snittegenskapen, og den er
ikke en formalitet — uten den er setningen om trygge kanter usann. BådeMST-Prim og MST-Kruskal er konstruert nettopp slik at snittet de bruker,
alltid respekterer de kantene de har valgt.
En kant som kan legges til en kantmengde uten at slutter å være en del
av et minimalt spenntre.
Presist: hvis er en delmengde av et MST, og kanten er trygg for ,
så er også en delmengde av et MST. «Trygg» betyr altså ikke
angre senere: du kan bygge videre og fortsatt havne på et optimalt tre. Hele
MST-teorien er ett spørsmål gjentatt ganger: hvilken kant er trygg nå?
være en kantmengde som er del av et minimalt spenntre for .
La være et snitt som respekterer — altså der ingen kant i
krysser snittet.
La være en letteste kant som krysser snittet, altså en kant med
minst mulig vekt blant alle som går mellom og .
Da er trygg for : mengden er fortsatt del
av et minimalt spenntre.
Ideen bak, i tre setninger. Anta at ligger i et MST som ikke
inneholder . Legger du til , får du en sykel, og den
sykelen må krysse snittet minst én gang til — la den andre kryssende kanten
hete . Bytt ut med : det er fortsatt et spenntre, det
inneholder fortsatt hele siden ikke lå i (snittet respekterer
), og vekten er ikke større fordi var en letteste kryssende kant.
Betingelsen er ufravikelig. Sløyfer du «som respekterer », er setningen
rett og slett usann — se moteksempelet i Eksempel 2. Det er også det
løsningsforslagene ser etter i en definisjonsoppgave om trygge kanter: nevner du
ikke betingelsen, mangler hovedpoenget.
Både Prim og Kruskal er denne setningen i praksis. De velger bare snittet
sitt på hver sin måte: Prim lar være nodene i treet som vokser, Kruskal lar
være komponenten til den ene enden av kanten den vurderer.
C–D (3). Sett og . Respekterer snittet
valgene dine? Hvilken kant er trygg?
b) Vis med et konkret eksempel at påstanden «den letteste kanten som krysser
et snitt er trygg» blir gal hvis vi dropper kravet om at snittet må
respektere valgene så langt.
, så ingen valgt kant krysser.
De kryssende kantene er A–B (4), B–C (5), D–E (6), C–E (8), B–D (10) og
D–F (11). Den letteste er A–B med vekt 4, og den er derfor trygg: du kan
legge den til uten å ødelegge muligheten for å ende på et minimalt spenntre.
Grafen har nøyaktig ett minimalt spenntre — A–C (2), C–D (3), A–B (4), D–E (6),
E–F (7), F–G (1), med total vekt 23 — og A–B ligger i det.
b) Moteksempelet. Fire målestasjoner K, L, M og N med disse fem strekningene:
K-L 5 K-M 5 K-N 7 L-M 10 M-N 7Grafen har to minimale spenntrær, begge med vekt 17: og
.
Anta at du har valgt — en lovlig start, siden den
er del av det siste av de to trærne. Velg nå snittet ,
. Dette snittet respekterer ikke : kanten K–N krysser det.
De kryssende kantene er K–N (7) og M–N (7). Begge er letteste kryssende kant.
Velger du M–N, får du — og det er ingen
delmengde av noe spenntre i det hele tatt, for de tre kantene danner rundturen
K, M, N, K.
Poenget i én linje: uten betingelsen kan «letteste kryssende kant» være
nettopp den kanten som lukker en sykel med noe du allerede har valgt. Det er
derfor både Prim og Kruskal er nøye med hvilket snitt de bruker.
Forklar MST-snittstrategien med egne ord.
a) Hva vil det si at en kant er trygg?
b) Formulér snittegenskapen presist, med alle betingelsene.
c) Hvorfor kan ikke betingelsen om at snittet respekterer valgene, sløyfes?
spenntre. Er to eller flere kantvekter like, kan den ha flere — alle med samme
totale vekt.
Det motsatte gjelder ikke: like kantvekter kan gi flere minimale
spenntrær, men trenger ikke. En graf med to like vekter som ikke ligger på noen
felles sykel, har fortsatt ett eneste MST.
Et eksempel med to svar. Fire pumpestasjoner i en firkant, med
strekningene K–L (1), L–M (2), M–N (1) og K–N (2). Et spenntre må droppe
nøyaktig én av de fire kantene, og for å få minst mulig vekt må den som droppes
ha vekt 2. Det gir to forskjellige minimale spenntrær:
- K–L (1), L–M (2), M–N (1) — vekt 4
- K–L (1), K–N (2), M–N (1) — vekt 4
Begge er riktige svar. Blir du bedt om «et minimalt spenntre», leverer du ett av
dem; blir du bedt om «det minimale spenntreet» i en graf med like vekter, er
selve spørsmålet upresist, og du bør skrive at treet ikke er entydig.
På eksamen: påstanden «MST-et er entydig» er en klassisk sjanger F-oppgave.
Riktig svar er nei, med betingelsen: entydige kantvekter gir entydig
minimalt spenntre.
En kandidat skriver: «En sammenhengende graf har alltid nøyaktig ett
minimalt spenntre.»
a) Stemmer dette? Svar ja eller nei først.
b) Gi et moteksempel med tall.
c) Under hvilken betingelse er påstanden riktig?
Kruskal: billigste kant først, hopp over dem som lukker en ring (~14 min)
— naturlig pausepunkt —
Den første av de to algoritmene tenker som en innkjøper: sorter alle traseene
etter pris, og gå gjennom lista fra billigst til dyrest. For hver trasé stiller
du ett spørsmål — henger disse to grendene allerede sammen? Gjør de det, er
traseen unødvendig, og du hopper over den. Gjør de det ikke, bygger du den.
Underveis har du altså ikke ett tre, men en samling atskilte biter som gradvis
smelter sammen. Det er nøyaktig det Union-Find fra
kap. 3.5 er laget for: Find-Set svarer på om to noder
er i samme bit, Union slår to biter sammen.
Snittegenskapen forklarer hvorfor det er riktig. Når MST-Kruskal vurderer den
letteste gjenværende kanten mellom to biter, kan du sette til den ene biten
og til resten. Alle kanter valgt så langt ligger inne i biter, så snittet
respekterer dem — og kanten er den letteste som krysser, siden alle lettere
kanter allerede er behandlet.
vektet med . Kantene ligger i en liste som kan sorteres.
Union-Finder en skog av disjunkte mengder, én mengde per node i starten. Kanter med lik
vekt sorteres i en fast, oppgitt rekkefølge, slik at håndkjøringen blir
entydig — i denne boka alfabetisk på nodenavn.
Prebetingelse: grafen er sammenhengende. Postbetingelse: A er et
minimalt spenntre med nøyaktig kanter.
MST-Kruskal(G, w)
Input: urettet sammenhengende vektet graf G = (V, E)
Output: A, et minimalt spenntre
A = tom mengde
for hver node v i V
Make-Set(v)
sorter kantene i E stigende etter vekt w(u,v)
for hver kant (u,v) i E, i sortert rekkefolge
if Find-Set(u) != Find-Set(v)
A = A forent med {(u,v)}
Union(u, v)
return A
Kjoretid: O(E lg V)Invarianten i én setning: før hver runde er A en delmengde av et minimalt
spenntre, og Union-Find-mengdene er nøyaktig komponentene A deler grafen i.
Kjøretid : sorteringen av kanter koster , og siden
er , så . De kallene tilMake-Set og de kallene til Find-Set og Union koster til sammen
mindre enn dette. Sorteringen dominerer — det er det svaret en
kjøretidsoppgave er ute etter.
Kjør MST-Kruskal på fibergrafen med de elleve traseene:
A-B 4 A-C 2 B-C 5 B-D 10
C-D 3 C-E 8 D-E 6 D-F 11
E-F 7 E-G 9 F-G 1Kanter med lik vekt behandles alfabetisk. Oppgaven ber om kantene i den
rekkefølgen de legges til, ikke om en forklaring av algoritmen.
F–G (1), A–C (2), C–D (3), A–B (4), B–C (5), D–E (6), E–F (7), C–E (8),
E–G (9), B–D (10), D–F (11)
Sporingstavlen. Én rad per kant i sortert rekkefølge, uten unntak — også de
som forkastes.
| Steg | Kant | Vekt | Avgjørelse | Komponentene etter steget |
|---|---|---|---|---|
| 1 | F–G | 1 | legges til | {A} {B} {C} {D} {E} {F,G} |
| 2 | A–C | 2 | legges til | {A,C} {B} {D} {E} {F,G} |
| 3 | C–D | 3 | legges til | {A,C,D} {B} {E} {F,G} |
| 4 | A–B | 4 | legges til | {A,B,C,D} {E} {F,G} |
| 5 | B–C | 5 | forkastes — lager sykel | {A,B,C,D} {E} {F,G} |
| 6 | D–E | 6 | legges til | {A,B,C,D,E} {F,G} |
| 7 | E–F | 7 | legges til | {A,B,C,D,E,F,G} |
| 8 | C–E | 8 | forkastes — lager sykel | {A,B,C,D,E,F,G} |
| 9 | E–G | 9 | forkastes — lager sykel | {A,B,C,D,E,F,G} |
| 10 | B–D | 10 | forkastes — lager sykel | {A,B,C,D,E,F,G} |
| 11 | D–F | 11 | forkastes — lager sykel | {A,B,C,D,E,F,G} |
På eksamen leverer du bare linjene under — tavlen er her for å vise hvordan du
kommer dit.
Kantene i den rekkefølgen de legges til: F–G (1), A–C (2), C–D (3), A–B (4),
D–E (6), E–F (7)
Forkastet, i den rekkefølgen de vurderes: B–C (5), C–E (8), E–G (9), B–D (10),
D–F (11)
Total vekt:
Legg merke til to ting. For det første at treet er ferdig etter steg 7 — da
har det kanter — men algoritmen går videre gjennom lista og forkaster
resten. En implementasjon kan gjerne stoppe der; håndkjøringen din bør likevel
vise hvorfor de gjenværende kantene ikke kan brukes. For det andre at B–C (5)
forkastes selv om den er lettere enn både D–E (6) og E–F (7): rekkefølgen i
lista avgjør ikke alene, sykeltesten gjør.
Fellenote. Fellen er å oppgi alle kantene, også de forkastede, uten å merke
dem — eller å legge til en kant som lager en sykel. Sjekk til slutt at du har
nøyaktig kanter.
Et strømnett har seks
transformatorpunkter og disse ni mulige linjene, med kostnad i millioner:
A-B 7 A-C 3 B-C 5 B-D 2
C-D 8 C-E 6 D-E 9 D-F 4
E-F 1Kjør MST-Kruskal. Oppgaven ber om kantene i den rekkefølgen de legges til,
samt hvilke som forkastes.
Prim: ett tre som vokser utover (~12 min)
Den andre algoritmen tenker som en entreprenør med én gravemaskin. Han starter i
én grend og bygger seg utover: i hver runde velger han den billigste traseen som
går fra det ferdige nettet til en grend som ennå ikke har fiber.
Forskjellen fra Kruskal er at Prim aldri har flere biter samtidig. Det er alltid
ett sammenhengende tre som vokser. Til gjengjeld må han hele tiden vite hvilken
node utenfor treet som er billigst å hente inn, og det er en jobb for en
prioritetskø: hver node utenfor treet har et felt key med vekten på den
letteste kjente kanten inn til treet, og Extract-Min gir noden med lavestkey.
Snittegenskapen igjen: la være nodene i treet og resten. Ingen valgt
kant krysser, siden alle valgte kanter ligger inne i treet — så snittet
respekterer valgene, og den letteste kryssende kanten er trygg. Det er nøyaktig
den kanten Extract-Min peker ut.
vektet, gitt som nabolister. Hver node
v har feltene v.key og v.pi. Q eren prioritetskø over nodene, ordnet etter
key, med Extract-Min ogDecrease-Key i hver med binærhaug. Ved lik key bryter vi likhetalfabetisk på nodenavn, slik at håndkjøringen blir entydig.
Prebetingelse: grafen er sammenhengende, og r er en node i den.
Postbetingelse: pi-feltene beskriver et minimalt spenntre: kantene
for alle unntatt rota r.
MST-Prim(G, w, r)
Input: urettet sammenhengende vektet graf G, rotnode r
Output: v.pi for hver node, som til sammen gir et minimalt spenntre
for hver node u i V
u.key = uendelig
u.pi = NIL
r.key = 0
Q = alle noder i V
while Q ikke er tom
u = Extract-Min(Q)
for hver v i Adj[u]
if v er i Q og w(u,v) < v.key
v.pi = u
Decrease-Key(Q, v, w(u,v))
Kjoretid: O(E lg V)Invarianten i én setning: før hver runde er kantene for nodene
som ikke står i Q, del av et minimalt spenntre, og v.key er vekten på den
letteste kanten fra treet til v for alle v som fortsatt står i Q.
Kjøretid : Extract-Min kalles ganger à , altså
, og Decrease-Key kalles høyst én gang per kantpost, altså
ganger à . Summen er for en
sammenhengende graf, der .
Rota spiller ingen rolle for svaret. Starter du et annet sted, får du
kantene i en annen rekkefølge, men — når kantvektene er entydige — det samme
treet.
Kjør MST-Prim på fibergrafen fra Eksempel 1 med rota A. Oppgi hvilken nodeExtract-Min gir i hver runde, hvilken kant som blir med i treet, ogkey-verdiene underveis.
A-B 4 A-C 2 B-C 5 B-D 10
C-D 3 C-E 8 D-E 6 D-F 11
E-F 7 E-G 9 F-G 1key-kolonnen viser verdiene rett etter runden; en strekbetyr at noden er tatt ut av køen.
| Runde | Extract-Min gir | Kant som blir med i treet | Oppdateringer | key for nodene som fortsatt står i køen |
|---|---|---|---|---|
| 1 | A | - | B.key: uendelig til 4, B.pi = A; C.key: uendelig til 2, C.pi = A | A=-, B=4, C=2, D=uendelig, E=uendelig, F=uendelig, G=uendelig |
| 2 | C | A–C (2) | D.key: uendelig til 3, D.pi = C; E.key: uendelig til 8, E.pi = C | A=-, B=4, C=-, D=3, E=8, F=uendelig, G=uendelig |
| 3 | D | C–D (3) | E.key: 8 til 6, E.pi = D; F.key: uendelig til 11, F.pi = D | A=-, B=4, C=-, D=-, E=6, F=11, G=uendelig |
| 4 | B | A–B (4) | ingen | A=-, B=-, C=-, D=-, E=6, F=11, G=uendelig |
| 5 | E | D–E (6) | F.key: 11 til 7, F.pi = E; G.key: uendelig til 9, G.pi = E | A=-, B=-, C=-, D=-, E=-, F=7, G=9 |
| 6 | F | E–F (7) | G.key: 9 til 1, G.pi = F | A=-, B=-, C=-, D=-, E=-, F=-, G=1 |
| 7 | G | F–G (1) | ingen | A=-, B=-, C=-, D=-, E=-, F=-, G=- |
På eksamen leverer du bare linjene under — tavlen er her for å vise hvordan du
kommer dit.
Kantene i den rekkefølgen Prim legger dem til: A–C (2), C–D (3), A–B (4),
D–E (6), E–F (7), F–G (1)
Forgjengerne:
A.pi = NIL, B.pi = A, C.pi = A, D.pi = C, E.pi = D,F.pi = E, G.pi = FTotal vekt:
Samme tre, annen rekkefølge. Kruskal i Eksempel 3 fant nøyaktig de samme
seks kantene, men i rekkefølgen F–G, A–C, C–D, A–B, D–E, E–F. Det er ventet:
grafen har entydige kantvekter, og da er det minimale spenntreet entydig.
Rekkefølgen kantene velges i, er derimot algoritmens egen.
Legg merke til runde 6. Da F ble hentet inn, falt G.key fra 9 til 1,
fordi F–G koster 1. Prim ser ikke framover — den oppdaget den billigste kanten i
hele grafen først i nest siste runde. Kruskal tok den først. Begge lander likevel
på 23, og det er snittegenskapen som garanterer det.
Fellenote. Fellen er å oppdatere key for en node som allerede er tatt ut av
køen. Testen i pseudokoden er if v er i Q, ikke bare «hvis vekten er lavere» —
en node som er hentet inn i treet, er ferdig.
Bruk strømnettet fra oppgave 4:
A-B 7 A-C 3 B-C 5 B-D 2
C-D 8 C-E 6 D-E 9 D-F 4
E-F 1Kjør MST-Prim med rota A. Oppgaven ber om rekkefølgen Extract-Min
henter nodene i, og kantene som velges — ikke om en forklaring av algoritmen.
MST-Kruskal, og hvilket steg dominerer?b) Hva er kjøretiden til
MST-Prim med binærhaug, og hvilke tooperasjonene utgjør den?
c) Hvorfor holder det ikke å bruke en vanlig usortert liste i stedet for
Union-Find i Kruskal?- Å tro at det minimale spenntreet er entydig. Det er det bare når alle
kantvektene er forskjellige. Skriv betingelsen — det er nettopp den som
skiller et fullt svar fra et halvt.
- Å legge til en kant som lager sykel i Kruskal. Kontrollen er Find-Set(u)
mot Find-Set(v), ikke øyemål på tegningen. Tell til slutt: har du flere enn
kanter, har du lagt til minst én for mye.
- Å liste alle kantene uten å merke de forkastede. Håndkjøringsoppgaven ber
om kantene i den rekkefølgen de legges til. Tar du med de forkastede uten
å merke dem, er svaret galt.
- Å hevde snittegenskapen uten betingelsen. «Den letteste kanten over et
snitt er trygg» er en ufullstendig — og som Eksempel 2 viser, gal — påstand.
Snittet må respektere kantene du har valgt.
- Å blande spenntre med et vilkårlig tre. Kantene må være grafens egne, og
alle noder må være med. En «snarvei» mellom to noder som ikke har en kant
mellom seg, finnes ikke.
- Å oppdatere key i Prim for en node som er tatt ut av køen. Testen er
if v er i Q. En node som er hentet inn i treet, har fått sin endelige kant.
Fire pumpestasjoner er knyttet sammen slik:
K-L 1 L-M 2 M-N 1 K-N 2a) Kjør MST-Kruskal med alfabetisk likhetsbryting, og oppgi kantene i den
rekkefølgen de legges til.
b) Hvor mange minimale spenntrær har grafen, og hva er vekten til hvert av
dem?
c) Hva ville skjedd med svaret ditt i a) hvis likhetsbrytingen hadde vært
motsatt alfabetisk?
Fem grender skal knyttes sammen med fiber. Traseene
og kostnadene er:
A-B 2 A-C 6 B-C 3 B-D 8
C-D 5 C-E 9 D-E 7Kommunen har allerede gravd grøfta mellom C og E, så den traseen må være med
i nettet uansett hva den koster.
a) Hva er det billigste nettet uten den bindingen?
b) Hvordan kan du bruke MST-Kruskal til å finne det billigste nettet som
inneholder C–E, uten å endre algoritmen? Kjør det.
c) Hva koster bindingen?
Kjøretidene samlet (~5 min)
| Algoritme/operasjon | Kjøretid | Hva som dominerer | Krav og egenskap |
|---|---|---|---|
MST-Kruskal | sorteringen av kantene | trenger Union-Find; bygger flere biter som smelter sammen | |
MST-Prim med binærhaug | kall til Decrease-Key | trenger prioritetskø; bygger ett sammenhengende tre | |
Make-Set, Find-Set, Union | nesten konstant hver | — | fra kap. 3.5; svarer på «henger disse sammen?» |
Extract-Min, Decrease-Key | hver | — | binærhaug fra kap. 3.1 |
| Sjekk om en kantmengde er et spenntre | én traversering | tell kantene () og sjekk at alt henger sammen |
Begge algoritmene er , så kjøretiden alene skiller dem ikke.
Forskjellen er praktisk: Kruskal vil ha kantene i en liste som kan sorteres,
Prim vil ha nabolister og en prioritetskø. Er kantene allerede sortert, er
Kruskal raskere; er grafen tett, gjør Prim færre operasjoner på hver node.
Merk
O framfor \Theta. Vi skriver fordi begge algoritmenekan stoppe tidlig i heldige tilfeller — Kruskal når treet har kanter,
lenge før lista er gjennomgått. Uttrykket er en øvre grense som alltid holder,
og det er det svaret en kjøretidsoppgave er ute etter.
Begrepsbank
Begrepsbanken er flashcard- og repetisjonsstoff — den gjentar det du nettopp har
lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder
kjernestoffet.
Finner et minimalt spenntre ved å sortere alle kantene stigende og legge til
hver kant som ikke lager en sykel.
Kjøretid , der sorteringen dominerer. Krever Union-Find for
sykeltesten: kanten forkastes når Find-Set(u) og Find-Set(v) gir samme svar.
Underveis har algoritmen en skog av flere biter, ikke ett tre. Svaret er kantene
i den rekkefølgen de legges til, med de forkastede merket.
Finner et minimalt spenntre ved å vokse ett sammenhengende tre fra en rot, og
alltid ta den letteste kanten ut av treet.
Kjøretid med binærhaug. Krever prioritetskø med Extract-Min ogDecrease-Key. Hver node utenfor treet har key = vekten på den letteste kjente
kanten inn til treet. Rota kan velges fritt: rekkefølgen på kantene endres, men
treet blir det samme når kantvektene er entydige.
Datastrukturen som holder styr på hvilke elementer som ligger i samme mengde,
uten at mengdene overlapper.
Fra kap. 3.5. Representeres som en skog: ett tre per
mengde, hver node peker på forelderen, roten er representanten. Med de to
standardgrepene — å henge det lave treet under det høye, og å la Find-Set
peke nodene rett på rota — er en følge av operasjoner så nær lineær at hver
operasjon regnes som nesten konstant. I MST-Kruskal er den sykeltesten.
De tre operasjonene på disjunkte mengder.
Make-Set(x) lager en ny mengde med bare x. Find-Set(x) gir representanten
for mengden x ligger i — to elementer er i samme mengde nøyaktig når svarene er
like. Union(x, y) slår de to mengdene sammen. I MST-Kruskal kallesMake-Set én gang per node, Find-Set to ganger per kant og Union én gang per
valgt kant.
En kø der elementet med lavest nøkkel tas ut først, uansett når det kom inn.
Implementeres som en binærhaug fra kap. 3.1:Extract-Min i , Decrease-Key i . MST-Prim bruker den
til å finne den letteste kanten ut av treet uten å lete gjennom alle kantene
hver runde. Det er den ene datastrukturen som gjør Prim raskere enn en naiv
-gjennomgang.
De to feltene hver node har under MST-Prim.
v.key er vekten på den letteste kjente kanten fra treet til v, og er
helt til treet får en nabo av v. v.pi er noden i treet den kanten
går fra. Når v hentes ut av køen, blir kanten med i spenntreet.
Felles for begge: de skal aldri oppdateres for en node som allerede er tatt
ut av køen.
En samling trær — altså en graf uten sykler, som ikke behøver å henge sammen.
Et spenntre er en skog med nøyaktig én komponent. MST-Kruskal har en skog
gjennom hele kjøringen: den starter med enkeltnoder, og hver kant som legges
til reduserer antall trær med én. Etter vellykkede kanter er det ett
igjen, og det er svaret.
En graf der det finnes en sti mellom hvert par av noder.
Dette er kravet for at et spenntre i det hele tatt skal finnes — er grafen delt
i to, kan ingen kantmengde nå alle nodene. Testen er én traversering fra en
vilkårlig node, i etter kap. 4.1: nås
alle nodene, henger grafen sammen. Både MST-Prim og MST-Kruskal forutsetter
det.
Tallet som er festet til kanten mellom og : kostnad, lengde, tid eller
kapasitet.
I MST-sammenheng kan vektene være negative uten at noe går galt — algoritmene
sammenligner bare kanter med hverandre, og en negativ vekt gjør bare kanten mer
attraktiv. Det er en viktig kontrast til korteste vei i
kap. 4.3, der negative vekter er et reelt problem forDijkstra.
Et tre med noder har nøyaktig kanter.
Dette er den billigste kontrollregningen i kapitlet. Har svaret ditt flere enn
kanter, har du lagt til en kant som lager en sykel. Har det færre, henger
ikke alle nodene sammen. Motsatt vei: en sammenhengende graf med nøyaktig
kanter er et tre, og dermed sitt eget minimale spenntre.
En algoritme som tar det beste valget her og nå, uten å gå tilbake på det
senere.
Både MST-Prim og MST-Kruskal er grådige: de tar alltid den letteste
tilgjengelige kanten. Grådighet gir ikke alltid riktig svar — for de fleste
problemer gjør den ikke det — men her gjør den det, og snittegenskapen er
beviset. Den sier nøyaktig at det grådige valget er trygt.
Et minimalt spenntre er entydig når alle kantvektene i grafen er forskjellige.
Er to kantvekter like, kan grafen ha flere minimale spenntrær — alle med
samme totale vekt. Den totale vekten er alltid entydig; det er utvalget av
kanter som kan variere. Derfor sier oppgavetekster «finn et minimalt
spenntre», og derfor oppgir håndkjøringsoppgaver en likhetsbryting.
Blant alle kantene som krysser et snitt, en av dem med minst vekt.
Ordet «en av dem» er med vilje: er det uavgjort mellom to kanter, er begge en
letteste kryssende kant, og begge er trygge. Det er dette som gjør at en graf
med like kantvekter kan ha flere minimale spenntrær. MST-Prim finner den medExtract-Min; MST-Kruskal finner den ved at kantene behandles i sortert
rekkefølge.
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.