TDT4120 Algoritmer og datastrukturer Interaktivt kompendium · H2026
Fremgang
0/15

06

Dynamisk programmering

Kjernepensum

Splitt og hersk deler en instans i delinstanser uten noe felles og løser hver av dem én gang. I mange problemer trengs den samme delinstansen av flere større instanser, og en rekursiv prosedyre løser den på nytt hver gang. Dynamisk programmering dekomponerer på samme måte som den rekursive prosedyren, men lagrer hvert delsvar første gang det regnes ut. Da er kjøretiden som regel lineær i antall forskjellige delinstanser og avhengighetene mellom dem, ikke i antall kall, og det kan være forskjellen på polynomisk og eksponentiell tid.

Stavkapping

En stav med lengde nn skal kappes i biter med heltallige lengder og selges. En bit med lengde ii gir prisen pip_i, og målet er størst mulig totalpris rnr_n. Prisene i eksemplene er p1,…,p8=1,5,8,9,10,17,17,20p_1, \ldots, p_8 = 1, 5, 8, 9, 10, 17, 17, 20. Staven kan kappes eller ikke i hvert av de n−1n - 1 heltallige punktene, så det finnes 2n−12^{n-1} kappinger. For n=4n = 4 er to biter med lengde 2 best, til 5+5=105 + 5 = 10 kr.

Dekomponer ved å velge det første kuttet. Gir det en bit med lengde ii, får du pip_i for den, og resten er en stav med lengde n−in - i, en mindre instans av samme problem. Totalprisen er pip_i pluss prisen for resten, så den blir størst når resten kappes optimalt: var resten kappet dårligere, kunne du byttet ut den kappingen og fått en bedre kapping av hele staven. Det beste med første bit ii er altså pi+rn−ip_i + r_{n-i}. En av de nn lengdene er den første biten i en optimal kapping, så du prøver alle og tar den beste:

r0=0rn=max⁡1≤i≤n(pi+rn−i)r_0 = 0 \allowbreak\quad r_n = \max_{1 \le i \le n} (p_i + r_{n-i})

Cut-Rod er denne rekurrensen skrevet som rekursiv prosedyre. Den er riktig, men treg. Kallet på lengde nn kaller seg selv på alle lengder fra n−1n - 1 ned til 0, og hvert av dem gjør det samme. Antall kall T(n)T(n) er ett for rota pluss alle kallene under de nn barna:

T(n)=1+∑j=0n−1T(j)T(n) = 1 + \sum_{j=0}^{n-1} T(j)

Trekk fra den samme ligningen for n−1n - 1. Da faller 1 og leddene T(0),…,T(n−2)T(0), \ldots, T(n-2) bort, og bare T(n−1)T(n-1) står igjen:

T(n)−T(n−1)=T(n−1)  ⇒  T(n)=2T(n−1)  ⇒  T(n)=2nT(n) - T(n-1) = T(n-1) \;\Rightarrow\; T(n) = 2T(n-1) \;\Rightarrow\; T(n) = 2^n

Det siste steget bruker T(0)=1T(0) = 1, for kallet på lengde 0 kaller ingenting. Cut-Rod gjør altså like mye arbeid som å prøve alle kappingene.

Overlappende delinstanser og memoisering

Cut-Rod løser de samme delinstansene om og om igjen. Kallet på lengde 4 kaller lengde 2 direkte, og kallet på lengde 3 kaller lengde 2 én gang til. I hele kalltreet for n=4n = 4 kalles lengde 1 fire ganger og lengde 0 åtte ganger. Det finnes bare n+1n + 1 forskjellige delinstanser, lengdene 0 til nn, men 2n2^n kall.

Delinstansene er overlappende når flere instanser bygger på den samme delinstansen, direkte eller indirekte. Skjer det på mange nivåer, blir den rekursive løsningen eksponentiell. I splitt og hersk skjer det ikke. Merge-Sort deler tabellen i to halvdeler uten felles elementer, og hver delinstans trengs av bare én større instans.

Delinstansgrafen har én node per forskjellig delinstans, og en kant fra uu til vv når svaret for vv bygger på svaret for uu. For stavkapping er nodene lengdene 0 til nn, med en kant fra jj til kk for hver j<kj < k. Læreboka tegner kantene motsatt vei, og retningen spiller ingen rolle så lenge det er klart hva som bygger på hva. Grafen må være asyklisk, og hver kjede av avhengigheter må ende i et grunntilfelle. Ellers bygger en instans til slutt på seg selv, og rekursjonen stopper aldri. Kalltreet har én node for hver sti i grafen som ender i instansen, så en delinstans med mange stier til instansen står mange steder i treet.

Memoisering gir prosedyren hukommelse. Første gang den kalles med et argument, regner den ut svaret og lagrer det. Senere kall med samme argument slår opp svaret og returnerer med en gang. For stavkapping holder en tabell r[0..n]r[0 .. n] der −∞-\infty betyr at delinstansen ikke er løst. Uten de tre linjene som leser og skriver rr, er aux under nøyaktig Cut-Rod.

memoized_cut_rod.py
from math import inf

def memoized_cut_rod(p, n):  # p[0] er ubrukt, p[i] er prisen for lengde i
  r = [-inf] * (n + 1)
  return aux(p, n, r)

def aux(p, n, r):
  if r[n] >= 0:
      return r[n]
  if n == 0:
      q = 0
  else:
      q = -inf
      for i in range(1, n + 1):
          q = max(q, p[i] + aux(p, n - i, r))
  r[n] = q
  return q
Memoized-Cut-Rod
0 / 0

Treet øverst er alle kallene Cut-Rod gjør uten memo, i den rekkefølgen den memoiserte versjonen går gjennom dem. Et oransje kall er et oppslag i rr, og de bleke kallene under det blir aldri gjort. Raden nederst er rr, buene over den er kantene i delinstansgrafen, og grønt er løst og lagret.

Med memo beregnes hver lengde kk én gang, og den beregningen har kk runder i løkka. Til sammen er det 1+2+⋯+n=Θ(n2)1 + 2 + \cdots + n = \Theta(n^2) kall utover det første, ett per kant i delinstansgrafen.

Nedenfra og opp

Rekursjonen i den memoiserte versjonen sørger bare for at en delinstans er løst før noen bygger på den. Du kan like gjerne sørge for det direkte, ved å løse delinstansene i en rekkefølge der hver av dem kommer etter alle den bygger på. En slik rekkefølge er en topologisk sortering av delinstansgrafen, og for stavkapping er det bare 0,1,…,n0, 1, \ldots, n. Denne formen kalles iterasjon nedenfra og opp, bottom-up, og memoisering kalles tilsvarende ovenfra og ned, top-down. Bottom-Up-Cut-Rod fyller rr fra venstre, og når den kommer til r[j]r[j], er r[0..j−1]r[0 .. j - 1] ferdige.

Tabellen rr gir bare den beste prisen. For å finne kappingen lagrer du også valget: s[j]s[j] er lengden på den første biten i en optimal kapping av lengde jj. Kappingen leses av bakfra. Skriv ut s[n]s[n], trekk den fra nn, og gjenta til n=0n = 0. For n=7n = 7 er s[7]=1s[7] = 1 og s[6]=6s[6] = 6, altså én bit med lengde 1 og én med lengde 6, til 1+17=181 + 17 = 18 kr.

bottom_up_cut_rod.py
from math import inf

def bottom_up_cut_rod(p, n):
  r = [0] * (n + 1)
  s = [0] * (n + 1)
  for j in range(1, n + 1):
      q = -inf
      for i in range(1, j + 1):
          if p[i] + r[j - i] > q:
              q = p[i] + r[j - i]
              s[j] = i
      r[j] = q
  return r, s

def print_cut_rod_solution(p, n):
  r, s = bottom_up_cut_rod(p, n)
  while n > 0:
      print(s[n])
      n = n - s[n]

De to løkkene gir Θ(n2)\Theta(n^2), som den memoiserte versjonen. Bottom-up slipper kallene og er som regel raskere med en konstant faktor. Memoisering løser bare delinstansene som faktisk trengs, og de kan være færre enn alle.

Generelt er kjøretiden summen av arbeidet med hver delinstans. Koster hver kant i delinstansgrafen konstant tid, er kjøretiden lineær i antall noder og kanter. Stavkapping har n+1n + 1 noder og n(n+1)/2n(n + 1)/2 kanter, altså Θ(n2)\Theta(n^2).

Optimal delstruktur

I en optimal kapping er resten etter den første biten selv kappet optimalt, ellers kunne du byttet den ut og fått en bedre kapping av hele staven. En optimal løsning består altså av optimale løsninger på delinstansene. Den egenskapen kalles optimal delstruktur, og den gjør rekurrensen for rnr_n riktig. I beviset bytter du som regel ut en del av en optimal løsning med en bedre løsning på delinstansen. Da blir hele løsningen bedre, men den var optimal.

Korteste vei har optimal delstruktur. Går en korteste vei fra 1 til 4 innom 2, er delen fra 1 til 2 en korteste vei, ellers kunne den byttes ut med en kortere. Lengste enkle vei har ikke optimal delstruktur. Ta en firkant med kantene 1–2, 2–4, 4–3 og 3–1. En lengste enkel vei fra 1 til 4 er 1, 2, 4, men delen fra 1 til 2 er ingen lengste enkel vei, for 1, 3, 4, 2 er lengre. De lengste enkle veiene fra 1 til 2 og fra 2 til 4 er 1, 3, 4, 2 og 2, 1, 3, 4, og satt sammen besøker de 1, 3 og 4 to ganger. De to delene konkurrerer om de samme nodene, og en node den ene bruker, kan ikke den andre bruke. Ingen kjenner en effektiv algoritme for lengste enkle vei.

Dynamisk programmering trenger begge egenskapene: optimal delstruktur for at dekomponeringen skal gi riktig svar, og overlappende delinstanser for at det skal lønne seg å lagre delsvarene.

Læreboka gir en oppskrift i fire trinn, og stavkapping gikk gjennom alle fire.

  1. Struktur

    Beskriv hvordan en optimal løsning er bygd opp, og hvilket valg som deler den i delinstanser som selv må løses optimalt. For stavkapping er valget lengden ii på den første biten, og resten er en stav med lengde n−in - i.

  2. Rekurrens

    Definer verdien av en optimal løsning rekursivt, med grunntilfeller. For stavkapping er rekurrensen r0=0r_0 = 0 og rn=max⁡1≤i≤n(pi+rn−i)r_n = \max_{1 \le i \le n} (p_i + r_{n-i}).

  3. Verdi

    Regn ut verdien, med memoisering eller nedenfra og opp. Memoized-Cut-Rod og Bottom-Up-Cut-Rod fyller begge rr i Θ(n2)\Theta(n^2).

  4. Løsning

    Lagre valgene underveis, og les løsningen av bakfra. Bottom-Up-Cut-Rod lagrer den første biten i s[j]s[j], og kappingen leses av fra s[n]s[n].

Eksamensoppgave Rettferdig fordeling av kontorer
Kontinuasjonseksamen, august 2025, oppgave 12

Innen fagfeltet rettferdig fordeling (fair allocation) finnes det et bestemt problem, der man vil fordele nodene i en graf på et sett med mottakere, så rettferdig som mulig, slik at nodene hver mottaker får utgjør en sammenhengende graf. Det kan f.eks. være snakk om å fordele kontor på ulike grupper, der kantene i grafen angir hvilke kontor som er nabokontor, og hver gruppe vil ha et sett med kontor som ligger samlet.

Du skal løse et spesialtilfelle av dette, der alle kontorene ligger på samme side i en korridor, så grafen utgjør en sti.

For enkelhets skyld, antar vi at alle gruppene er enige om hvor fine kontorene er, så hvert kontor får en verdi i form av et positivt tall. Vi ønsker å finne en maksimin-fordeling, som er rettferdig i den forstand at den gruppen som får den laveste totalverdien likevel får en så høy totalverdi som mulig.

Hvordan vil du løse dette problemet? Forklar.

Merk at vi her kun ser på totalverdien hver gruppe får, og ikke har noe krav til antallet kontor. Vi kan f.eks. anta at verdien henger sammen med størrelsen, dvs. antall personer det er plass til, så færre og bedre kontor er like ønskelig som flere og dårligere.

Vis løsning Skjul løsning

Nummerer kontorene 1,…,n1, \ldots, n langs korridoren, med verdier a1,…,ana_1, \ldots, a_n, og la kk være antall grupper. Hver gruppe får et sammenhengende stykke av stien, så en fordeling er k−1k - 1 kutt, som i stavkapping.

Delinstansene trenger to parametre, antall grupper gg og antall kontorer jj fra starten av korridoren. La M[g,j]M[g, j] være den beste laveste totalverdien, og Sj=a1+⋯+ajS_j = a_1 + \cdots + a_j prefikssummene, regnet ut på forhånd i lineær tid.

Velg det siste stykket: kontorene i+1,…,ji + 1, \ldots, j går til én gruppe, og de første ii fordeles på de andre g−1g - 1 gruppene. Den laveste totalverdien er da den minste av Sj−SiS_j - S_i, verdien til det siste stykket, og den laveste blant de g−1g - 1 andre gruppene. Det siste stykket ligger fast, så minimum blir størst når den laveste blant de andre er størst, altså når de første ii kontorene fordeles maksimin. Den laveste totalverdien er altså min⁡(M[g−1,i], Sj−Si)\min(M[g-1, i],\, S_j - S_i). Hver av de g−1g - 1 andre gruppene trenger minst ett kontor, og det siste stykket også, så ii går fra g−1g - 1 til j−1j - 1, og du tar den beste:

M[1,j]=SjM[g,j]=max⁡g−1≤i<jmin⁡(M[g−1,i], Sj−Si)M[1, j] = S_j \allowbreak\quad M[g, j] = \max_{g-1 \le i < j} \min(M[g-1, i],\, S_j - S_i)

Fyll MM nedenfra og opp for g=1,…,kg = 1, \ldots, k, eller memoiser rekursjonen. Det er knkn delinstanser med høyst nn valg hver, så kjøretiden er O(kn2)O(kn^2). Lagre det beste ii for hver delinstans, så kan fordelingen leses av bakfra fra M[k,n]M[k, n].

Svar
Som stavkapping: prøv alle størrelser på ett stykke, ta minimum av verdien til stykket og maksimin for resten med én gruppe mindre, og velg det beste. O(kn2)O(kn^2) med memoisering eller nedenfra og opp.

Lengste felles delsekvens

En delsekvens får du ved å stryke null eller flere elementer fra en sekvens og beholde rekkefølgen på resten. «baker» er en delsekvens av både «bakverk» og «basker», og ingen lengre felles delsekvens finnes. Problemet LCS er å finne en lengste felles delsekvens av X=⟨x1,…,xm⟩X = \langle x_1, \ldots, x_m \rangle og Y=⟨y1,…,yn⟩Y = \langle y_1, \ldots, y_n \rangle. LCS er grunnlaget for blant annet diff og for sammenligning av DNA-sekvenser. XX har 2m2^m delsekvenser, så å prøve alle er uaktuelt.

Delinstansene er prefikser, Xi=⟨x1,…,xi⟩X_i = \langle x_1, \ldots, x_i \rangle og YjY_j, og du dekomponerer ved å se på de siste elementene. La ZZ være en LCS av XiX_i og YjY_j. Er xi=yjx_i = y_j, må ZZ slutte på dette elementet, for ellers kunne du lagt det til bakerst og fått en lengre felles delsekvens. Resten av ZZ er da en felles delsekvens av Xi−1X_{i-1} og Yj−1Y_{j-1}, og den er en lengste, for ellers kunne du byttet den ut og fått en lengre ZZ. Er xi≠yjx_i \ne y_j, kan ikke det siste elementet i ZZ være lik begge, så ZZ er en felles delsekvens av Xi−1X_{i-1} og YjY_j eller av XiX_i og Yj−1Y_{j-1}. Du løser begge delinstansene og tar den beste. Med c[i,j]c[i, j] som lengden av en LCS av XiX_i og YjY_j:

c[i,j]={0i=0 eller j=0c[i−1,j−1]+1i,j>0 og xi=yjmax⁡(c[i−1,j], c[i,j−1])i,j>0 og xi≠yjc[i, j] = \begin{cases} 0 & i = 0 \text{ eller } j = 0 \\ c[i-1, j-1] + 1 & i, j > 0 \text{ og } x_i = y_j \\ \max(c[i-1, j],\, c[i, j-1]) & i, j > 0 \text{ og } x_i \ne y_j \end{cases}

Delinstansene overlapper, for både c[i−1,j]c[i-1, j] og c[i,j−1]c[i, j-1] bygger på c[i−1,j−1]c[i-1, j-1]. Delinstansgrafen er et rutenett med (m+1)(n+1)(m+1)(n+1) noder, der hver celle bygger på cellen over, cellen til venstre og cellen diagonalt over til venstre. Rad for rad fra venstre er derfor en topologisk rekkefølge.

LCS-Length fyller tabellen cc i den rekkefølgen og lagrer valget i bb som en pil mot cellen svaret kom fra. Print-LCS følger pilene bakfra fra b[m,n]b[m, n] og skriver ut xix_i for hver diagonal pil. Den skriver etter det rekursive kallet, så bokstavene kommer forfra selv om pilene følges bakfra.

lcs.py
def lcs_length(X, Y):
  m, n = len(X), len(Y)
  c = [[0] * (n + 1) for _ in range(m + 1)]
  b = [[""] * (n + 1) for _ in range(m + 1)]
  for i in range(1, m + 1):
      for j in range(1, n + 1):
          if X[i - 1] == Y[j - 1]:  # x_i og y_j
              c[i][j] = c[i - 1][j - 1] + 1
              b[i][j] = "↖"
          elif c[i - 1][j] >= c[i][j - 1]:
              c[i][j] = c[i - 1][j]
              b[i][j] = "↑"
          else:
              c[i][j] = c[i][j - 1]
              b[i][j] = "←"
  return c, b

def print_lcs(b, X, i, j):
  if i == 0 or j == 0:
      return
  if b[i][j] == "↖":
      print_lcs(b, X, i - 1, j - 1)
      print(X[i - 1], end="")
  elif b[i][j] == "↑":
      print_lcs(b, X, i - 1, j)
  else:
      print_lcs(b, X, i, j - 1)
LCS-Length og Print-LCS
0 / 0

Tabellen cc med XX nedover og YY bortover, og pilen fra bb i hjørnet av hver celle. Oransje er cellene den nye cellen leser, og fylt er cellen svaret kommer fra. Grønne celler har diagonal pil og ligger på veien Print-LCS følger, og bokstavene deres er LCS-en.

LCS-Length bruker konstant tid per celle, altså Θ(mn)\Theta(mn). Print-LCS tar høyst m+nm + n steg, for hvert kall minsker ii eller jj eller begge.

Eksamensoppgave Rekurrensen for LCS
Ordinær eksamen, desember 2025, oppgave 5

Dette er den rekursive formuleringen av lengden til den lengste felles delsekvensen (longest common subsequence, LCS) for prefiksene XiX_i og YjY_j av X og Y.

c[i,j]={0if i=0 or j=0 ,if i,j>0 and xi=yj ,max⁡{c[i,j−1],c[i−1,j]}if i,j>0 and xi≠yj .c[i, j] = \begin{cases} 0 & \text{if } i = 0 \text{ or } j = 0\,, \\ \rule[-0.15em]{6.5em}{0.8em} & \text{if } i, j > 0 \text{ and } x_i = y_j\,, \\ \max\{c[i, j-1], c[i-1, j]\} & \text{if } i, j > 0 \text{ and } x_i \neq y_j\,. \end{cases}

Hva er det som mangler? Forklar kort.

Vis løsning Skjul løsning

Linjen gjelder tilfellet der de siste elementene i prefiksene er like. Da må en LCS slutte på det elementet, for ellers kunne det legges til bakerst. Resten er en LCS av Xi−1X_{i-1} og Yj−1Y_{j-1}, for en lengre kunne byttet den ut, og lengden øker med 1.

Svar
c[i−1,j−1]+1c[i-1, j-1] + 1

Det binære ryggsekkproblemet

Du har nn gjenstander, der gjenstand ii har verdi viv_i og vekt wiw_i, og en ryggsekk med kapasitet WW, alle positive heltall. Velg gjenstander med størst mulig totalverdi og totalvekt høyst WW. Hver gjenstand er med eller ikke med, og det er derfor problemet kalles binært.

Dekomponer på spørsmålet om gjenstand nn skal være med. Nei gir det samme problemet med gjenstandene 1,…,n−11, \ldots, n - 1 og hele kapasiteten. Ja gir verdien vnv_n pluss det beste med gjenstandene 1,…,n−11, \ldots, n - 1 og kapasitet W−wnW - w_n, og er bare mulig hvis wn≤Ww_n \le W. Delinstansene trenger derfor to parametre: hvor mange gjenstander som er med i betraktningen, og hvor mye kapasitet som er igjen. Med K[i,j]K[i, j] som den største verdien med gjenstandene 1,…,i1, \ldots, i og kapasitet jj:

K[i,j]={0i=0K[i−1,j]wi>jmax⁡(K[i−1,j], K[i−1,j−wi]+vi)wi≤jK[i, j] = \begin{cases} 0 & i = 0 \\ K[i-1, j] & w_i > j \\ \max(K[i-1, j],\, K[i-1, j - w_i] + v_i) & w_i \le j \end{cases}

Rad ii bygger bare på rad i−1i - 1, så tabellen fylles rad for rad. Cellen som gir verdien med gjenstand ii, ligger wiw_i kolonner lenger til venstre, så kantene i delinstansgrafen avhenger av vektene. Valgene trenger ikke lagres for seg. Er K[i,j]≠K[i−1,j]K[i, j] \ne K[i-1, j], var gjenstand ii med, for uten den er det beste K[i−1,j]K[i-1, j]. Da fortsetter du fra K[i−1,j−wi]K[i-1, j - w_i]. Ellers fortsetter du fra K[i−1,j]K[i-1, j].

ryggsekk.py
def knapsack(v, w, W):  # gjenstand i har verdi v[i - 1] og vekt w[i - 1]
  n = len(v)
  K = [[0] * (W + 1) for _ in range(n + 1)]
  for i in range(1, n + 1):
      for j in range(W + 1):
          x = K[i - 1][j]
          if j < w[i - 1]:
              K[i][j] = x
          else:
              y = K[i - 1][j - w[i - 1]] + v[i - 1]
              K[i][j] = max(x, y)
  return K

def chosen(K, w, W):
  items, j = [], W
  for i in range(len(K) - 1, 0, -1):
      if K[i][j] != K[i - 1][j]:
          items.append(i)
          j = j - w[i - 1]
  return items
Knapsack′
0 / 0

Tabellen KK med én rad per gjenstand og én kolonne per kapasitet, og vekt ww og verdi vv til høyre. Oransje er cellene den nye cellen leser, rett over og wiw_i kolonner lenger til venstre i raden over, og den som gir størst verdi, er fylt. Grønt er gjenstandene som er med.

Tabellen har (n+1)(W+1)(n + 1)(W + 1) celler med konstant arbeid per celle, så kjøretiden er Θ(nW)\Theta(nW). Det ser polynomisk ut, men er det ikke som funksjon av inputstørrelsen, som måles i bits. Tallet WW tar bare m=⌊lg⁡W⌋+1m = \lfloor \lg W \rfloor + 1 bits å skrive, så WW vokser eksponentielt med plassen tallet tar:

Θ(nW)=Θ(n2m)\Theta(nW) = \Theta(n 2^m)

Ett bit til i WW kan altså doble kjøretiden. En kjøretid som er polynomisk i et tall fra inputen, men ikke i antall bits, kalles pseudopolynomisk. Er WW begrenset av et polynom i nn, er kjøretiden polynomisk. Med vilkårlig store heltall er ryggsekkproblemet NP-hardt, og ingen kjenner en algoritme som er polynomisk i antall bits.

Eksamensoppgave Er ryggsekkløsningen polynomisk?
Kontinuasjonseksamen, august 2024, oppgave 9

Løsningen på det binære ryggsekkproblemet (0-1 knapsack) har kjøretid Θ(nW)\Theta(nW), der nn er antall gjenstander og WW er kapasiteten til ryggsekken. Er dette en polynomisk algoritme? Forklar kort.

Vis løsning Skjul løsning

Polynomisk betyr polynomisk i inputstørrelsen, antall bits. WW tar m=Θ(lg⁡W)m = \Theta(\lg W) bits, og med mm bits kan WW være nesten 2m2^m. Da er Θ(nW)=Θ(n2m)\Theta(nW) = \Theta(n 2^m), som er eksponentielt i mm. Kjøretiden er pseudopolynomisk.

Svar
Nei. WW vokser eksponentielt med antall bits som trengs for å skrive det.

Sjekk deg selv

Du kaller Cut-Rod på en stav med lengde 5, uten memo. Hvor mange av kallene har lengde 1?
Oppdatert 27. september 2026 Foreslå endring