TDT4120 Algoritmer og datastrukturer Interaktiv pensumguide · H2026
Fremgang
0/14
09
Grafer

Minimale spenntrær

Kjernepensum ~40 min lesing · MST · Grådighet · Union-Find

Gitt en sammenhengende, vektet og urettet graf: hvilken minste kantmengde holder alt sammen til lavest pris? Svaret er et minimalt spenntre (MST) — et tre som spenner alle nodene med minst mulig total kantvekt. MST er skoleeksempelet på at grådighet faktisk gir et globalt optimum, og hele beviset hviler på ett presist begrep: trygge kanter.

Disjunkte mengder (union-find)

Disjunkte mengder vedlikeholder en partisjon av elementer under to operasjoner: Find-Set(x) returnerer representanten for mengden xx ligger i, og Union(x, y) slår sammen to mengder. Skogimplementasjonen lar hvert element peke mot en forelder; representanten er rota. To triks gjør operasjonene nesten konstante i amortisert tid:

  • Union ved rang — heng det lavere treet under det høyere, så trærne holder seg grunne.
  • Stikomprimering — pek hver besøkt node rett på rota under Find-Set.

Med begge er mm operasjoner O(mα(n))O(m\,\alpha(n)), der α\alpha er den (nesten konstante) inverse Ackermann-funksjonen. For oss er poenget at union-find lar Kruskal raskt svare på «ligger disse to nodene allerede i samme komponent?».

Spenntre og MST

Et spenntre av en sammenhengende graf er et asyklisk delsett av kantene som kobler alle noder; det har alltid nøyaktig V1|V| - 1 kanter. Et minimalt spenntre er et spenntre med minst mulig sum av kantvekter. Det trenger ikke være entydig — med like vekter kan flere MST eksistere — men den minimale totalvekten er det.

Generic-MST og trygge kanter

Begge algoritmene vi skal se er instanser av ett grådig skjelett. Vi holder på en delmengde AA av kanter som er en del av et MST, og legger til én trygg kant av gangen til AA er et helt spenntre.

Hva gjør en kant trygg? Et snitt (S,VS)(S, V \setminus S) deler nodene i to. En kant krysser snittet om endepunktene ligger på hver sin side. Et snitt respekterer AA om ingen kant i AA krysser det. Da gjelder:

Beviset er et klassisk utbyttingsargument: ta et MST TT som inneholder AA. Inneholder TT allerede (u,v)(u,v), er vi ferdige. Ellers lager (u,v)(u,v) en sykel sammen med stien i TT; den stien må krysse snittet via en annen kant (x,y)(x,y) med w(x,y)w(u,v)w(x,y) \ge w(u,v). Bytt (x,y)(x,y) mot (u,v)(u,v): resultatet er fortsatt et spenntre, med vekt som ikke er større — altså også et MST som inneholder A{(u,v)}A \cup \{(u,v)\}. Dette er det sentrale beviset i hele kapittelet.

Kruskals algoritme

Kruskal er Generic-MST med ett bestemt valg av snitt: sorter alle kantene etter vekt, og legg til hver kant som forbinder to ulike komponenter. En kant som ville koblet to noder i samme komponent forkastes — den ville lagd en sykel. Union-find er nettopp det som svarer på komponent-spørsmålet raskt.

kruskal.py
def kruskal(V, edges):
  parent = {v: v for v in V}
  def find(x):
      while parent[x] != x:
          x = parent[x]
      return x
  tree = []
  for u, v, w in sorted(edges, key=lambda e: e[2]):
      if find(u) != find(v):
          parent[find(u)] = find(v)
          tree.append((u, v, w))
  return tree
Kruskals algoritme

Interaktiv visualisering krever JavaScript.

0 / 0

Kantene behandles fra lettest til tyngst. Grønne kanter er godtatt (med i MST); røde stiplede er forkastet fordi de ville lagd en sykel. Sub-merket under hver node er komponentrepresentanten dens — de smelter sammen etter hvert som Union kjøres.

Kruskal bruker O(ElgV)O(E \lg V) tid: sorteringen dominerer, og union-find-arbeidet er nesten lineært. Den sorterte rekkefølgen gjør hvert grådige valg trygt — hver godtatt kant er den letteste som krysser snittet mellom dens to komponenter og resten.

Prims algoritme

Prim velger et annet snitt: la AA alltid være ett sammenhengende tre som vokser ut fra en startnode. I hvert steg legger vi til den letteste kanten som forlater treet. En min-prioritetskø (en haug) over nodene utenfor treet, nøklet på letteste kjente kant inn til treet, gir nettopp denne kanten i logaritmisk tid. Prioritetskøen er hele motoren: med binær haug blir Prim O(ElgV)O(E \lg V), og med Fibonacci-haug O(E+VlgV)O(E + V \lg V).

Sjekk deg selv

Hva betyr det at en kant er trygg i MST-sammenheng?