• Keine Ergebnisse gefunden

Häufige Fehler

N/A
N/A
Protected

Academic year: 2022

Aktie "Häufige Fehler"

Copied!
58
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Datenstrukturen und Algorithmen

Christian Sohler

FG Algorithmen & Komplexität

(2)

Ergebnisse des Tests

(3)

Häufige Fehler

Unnötige Dinge:

• Aufgabenstellung nicht richtig gelesen

• Mehrfache Lösungen derselben Aufgabe

Teile & Herrsche:

• Aufruf mit 2 Unterproblemen (gibt nur Laufzeit O(n))

• Da beide Aufrufe x berechnen, benötigt man nur einen rekursiven Aufruf!

• Geometrische Reihe:

Σ

c = const für c<1 !!!

i=0

i

⎣n/2⎦

(4)

Häufige Fehler

Gieriger Algorithmus:

• Aufsteigend sortiert

• Sortieralgorithmus mit schlechter worst-case Laufzeit (Bubblesort, Quicksort,…) verwendet (Quicksort hat worst-case Laufzeit Θ(n²) !)

• Falsche Laufzeit für Quicksort, Mergesort,…

(5)

Dynamische Programmierung

Szenario:

• Maschine für W Zeitschritte zur Verfügung

• n Aufgaben, die von Maschine erledigt werden könnten

• Aufgaben benötigen unterschiedlich viel Zeit

• Reihenfolge und Zeitpunkt unerheblich

Ziel

• Sie wollen ihre Maschine möglichst gut auslasten

(6)

Dynamische Programmierung

Beispiel:

• 15 Zeiteinheiten stehen insgesamt zur Verfügung

Aufgabe 1 2 3 4 5 6 7 8 9

Zeit 8 3 5 2 2 4 3 11 13

(7)

Dynamische Programmierung

Beispiel:

• 15 Zeiteinheiten stehen insgesamt zur Verfügung

• Aufgabe 2 und Aufgabe 11 benötigen 14 Zeitschritte

Aufgabe 1 2 3 4 5 6 7 8 9

Zeit 8 3 5 2 2 4 3 11 13

(8)

Dynamische Programmierung

Beispiel:

• 15 Zeiteinheiten stehen insgesamt zur Verfügung

Aufgabe 1 2 3 4 5 6 7 8 9

Zeit 8 3 5 2 2 4 3 11 13

(9)

Dynamische Programmierung

Beispiel:

• 15 Zeiteinheiten stehen insgesamt zur Verfügung

• Aufgabe 2 und Aufgabe 11 benötigen 14 Zeitschritte

• Bessere Lösung möglich?

• Ja! Aufgabe 1,3 und 4 benötigen 15 Zeiteinheiten

Aufgabe 1 2 3 4 5 6 7 8 9

Zeit 8 3 5 2 2 4 3 11 13

(10)

Dynamische Programmierung

Subset Sum (Optimierungsvariante):

• Eingabe: Menge X mit n pos. Integers und ein Zielwert W

• Ausgabe: Menge S⊆X, so dass

Σ

x unter der Bedingung

Σ

x ≤ W maximiert wird

x∈S

x∈S

(11)

Dynamische Programmierung

Subset Sum (Entscheidungsvariante):

• Eingabe: Menge X mit n pos. Integers und ein Zielwert W

• Ausgabe: true, wenn es Menge S⊆X mit

Σ

x = W gibt

false, sonst x∈S

(12)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

(13)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do

Probiere alle Untermengen

aus

2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

(14)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Berechne Summe der Elemente in S

(15)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Falls Summe=W, dann Ausgabe

true

(16)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Falls es kein S gibt, das sich zu W

aufsummiert, Ausgabe false

(17)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Laufzeit:

(18)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

X S

31 ja 17 nein 13 ja 20 ja

(19)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Laufzeit:

X S

31 1

17 0

13 1

20 1

4 0

8 1

19 1

(20)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

X S

31 1

17 0

13 1

20 1

(21)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Laufzeit:

X S

31 1

17 0

13 1

20 1

4 0

8 1

19 1

Es gibt 2 viele Bitstrings der Länge n

n

(22)

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

X S

31 1

17 0

13 1

20 1

Dynamische Programmierung

(23)

Dynamische Programmierung

AusschöpfendeSuche(X,W)

1. for each subset S⊆X do 2. sum ← 0

3. for each x ← S do 4. sum ← sum + x

5. if sum = W return true 6. return false

Laufzeit:

X S

31 1

17 0

13 1

20 1

4 0

8 1

19 1

Wenn alle Rechner der Welt 100 Jahre rechnen würden,

könnten sie mit diesem Algorithmus ein Problem mit

500 Zahlen nicht lösen

(24)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

(25)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Aufruf:

• RekSubsetSum(X,W,length[X])

Hat X[1,…,n] eine Teilmenge S mit Gesamtwert W?

(26)

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Dynamische Programmierung

Die leere Menge hat Gesamtgewicht

W=0.

(27)

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Aufruf:

• RekSubsetSum(X,W,length[X])

Dynamische Programmierung

Da n=0 ist, betrachten wir nur noch die leere Menge.

Keine Teilmenge dieser Menge ist aufsummiert W≠0.

(28)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Ansonsten:

Logisches oder von zwei Fällen

(29)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Aufruf:

• RekSubsetSum(X,W,length[X])

S enthält X[n]:

Dann müssen wir in X[1,..,n-1]

eine Menge mit Gewicht W-X[n]

suchen

(30)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

S enthält nicht X[n]:

Dann müssen wir in X[1,..,n-1] eine Menge mit Gewicht W suchen

(31)

Dynamische Programmierung

RekSubsetSum(X,W,n)

1. if W=0 then return true 2. if n=0 return false

3. return (RekSubsetSum(X,W-X[n],n-1) or RekSubsetSum(X,W,n-1))

Laufzeit:

• Θ(2 )n

(32)

Dynamische Programmierung

Beobachtung:

• Es gibt maximal length[X]⋅W unterschiedliche Aufrufe von RekSubsetSum()

(33)

Dynamische Programmierung

Beobachtung:

• Es gibt maximal length[X]⋅W unterschiedliche Aufrufe von RekSubsetSum()

• Falls also length[X] ⋅ W << 2 ist, dann rufen wir RekSubsetSum() häufig mit denselben Parametern auf

length[X]

(34)

Dynamische Programmierung

Beobachtung:

• Es gibt maximal length[X]⋅W unterschiedliche Aufrufe von RekSubsetSum()

• Falls also length[X] ⋅ W << 2 ist, dann rufen wir RekSubsetSum() häufig mit denselben Parametern auf

• Wir lösen also dasselbe (Unter-)Problem mehrfach!

length[X]

(35)

Dynamische Programmierung

Beobachtung:

• Es gibt maximal length[X]⋅W unterschiedliche Aufrufe von RekSubsetSum()

• Falls also length[X] ⋅ W << 2 ist, dann rufen wir RekSubsetSum() häufig mit denselben Parametern auf

• Wir lösen also dasselbe (Unter-)Problem mehrfach!

Verbesserung des Algorithmus:

• Speichere berechnete Lösungen zwischen

• Falls Lösung ein zweites mal berechnet werden soll, gib

length[X]

(36)

Dynamische Programmierung

Beobachtung:

• Es gibt maximal length[X]⋅W unterschiedliche Aufrufe von RekSubsetSum()

• Falls also length[X] ⋅ W << 2 ist, dann rufen wir RekSubsetSum() häufig mit denselben Parametern auf

• Wir lösen also dasselbe (Unter-)Problem mehrfach!

length[X]

Kernidee des dynamischen Programmierens!

(37)

Dynamische Programmierung

Lösungsmatrix A

• A ist undef, wenn noch keine Lösung berechnet wurde

• A[i,j] = true, wenn es Teilmenge von X[1,..,j] gibt, deren Summe i ist

• A[i,j] = false, wenn es keine solche Teilmenge gibt

(38)

Dynamische Programmierung

InitSubsetDynamic(X,W,n) 1. for i←0 to W do

2. for j←0 to n do 3. A[i,j]←undef 4. for i←1 to W do 5. A[i,0]←false 6. for j←0 to n do

(39)

Dynamische Programmierung

InitSubsetDynamic(X,W,n) 1. for i←0 to W do

2. for j←0 to n do 3. A[i,j]←undef 4. for i←1 to W do 5. A[i,0]←false 6. for j←0 to n do 7. A[0,j]←true

6. RekSubsetDynamic(A,X,W,n)

Initialisiere Lösungsmatrix A

(40)

Dynamische Programmierung

InitSubsetDynamic(X,W,n) 1. for i←0 to W do

2. for j←0 to n do 3. A[i,j]←undef 4. for i←1 to W do 5. A[i,0]←false 6. for j←0 to n do

Eine Teilmenge der leeren Menge kann

nicht

(41)

Dynamische Programmierung

InitSubsetDynamic(X,W,n) 1. for i←0 to W do

2. for j←0 to n do 3. A[i,j]←undef 4. for i←1 to W do 5. A[i,0]←false 6. for j←0 to n do 7. A[0,j]←true

6. RekSubsetDynamic(A,X,W,n)

Die leere Menge summiert sich zu 0

auf

(42)

Dynamische Programmierung

InitSubsetDynamic(X,W,n) 1. for i←0 to W do

2. for j←0 to n do 3. A[i,j]←undef 4. for i←1 to W do 5. A[i,0]←false

6. for j←0 to n do Aufruf des

(43)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

7. else return A[W,n-1]

(44)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

Falls A[W,n-1] nicht bekannt ist, rechne

es aus

(45)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

7. else return A[W,n-1]

Falls A[W-X[n],n-1] definiert…

(46)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

(47)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

7. else return A[W,n-1]

Gib den richtigen Wert zurück.

(48)

Dynamische Programmierung

RekSubsetDynamic(A,X,W,n) 1. if A[W,n-1]=undef then

2. A[W,n-1]=RekSubsetDynamic(A,X,W,n-1) 3. if W≥X[n] then

4. if A[W-X[n], n-1]=undef then

5. A[W-X[n], n-1]=RekSubsetDynamic(A,X,W-X[n], n-1) 6. return (A[W,n-1] or A[W-X[n],n-1])

(49)

Dynamische Programmierung

Eine neue Implementierung:

• Bottom-up Berechnung (häufig einfacher)

• Matrix A[0,…,W]

• A[i] = true, gdw. es eine Untermenge mit Wert i gibt

Initialisierung:

• A[0]=true

• A[i]=false für alle i>0

• Nach Initialisierung korrektes A für leere Menge

(50)

Dynamische Programmierung

Annahme:

• A korrekt berechnet für X[1,…,k]

• Wie können wir A für X[1,…,k+1] bekommen?

Algorithmus:

• Wenn A[i] = true, dann setze A[i + X[k+1]] auf true

(51)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

7. if A[i]=true then A[i+X[j]]←true 8. return A[W]

(52)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

Initialisiere A

(53)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

7. if A[i]=true then A[i+X[j]]←true 8. return A[W]

Füge alle Elemente nacheinander ein

(54)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

Aktualisiere A

(55)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

7. if A[i]=true then A[i+X[j]]←true 8. return A[W]

Rückgabe des

(56)

Dynamische Programmierung

IterativeSubsetSum(X,W) 1. n←length[A]

2. A[0]←true

3. for i←1 to W do 4. A[i]←false

5. for j←1 to n do

6. for i←W downto 0 do

(57)

Dynamische Programmierung

Satz 19

Die Entscheidungsvariante des Subset Sum Problems kann in O(nW) Zeit exakt gelöst werden, wobei n die Eingabegröße ist und W der Zielwert.

Einschätzung des Algorithmus:

• Es ist kein effizienter Algorithmus für sehr großes W bekannt

• Ein solcher Algorithmus würde auch sehr viele andere Probleme effizient lösen (z.B. TSP)

(58)

Dynamische Programmierung

Zusammenfassung:

• Dynamische Programmierung vermeidet

Mehrfachberechnung von Zwischenergebnissen

• Bei Rekursion einsetzbar

• Häufig einfache bottom-up Implementierung möglich

• Algorithmus für schwieriges Problem (subset sum)

• Laufzeit hängt von Eingabewert W ab

Referenzen

ÄHNLICHE DOKUMENTE

Á  Á  Á QNM4rÍÒ?4FdBKP0plHlB = ©&amp; &amp;¾QNMRrÍD=AbB DGJIe&lt;W=WG?¤F5AKFœBEŽdFdM²ÙRUlW=W!JODGMND=J&amp;UlW ;QÕJ rg¥NMNM!?¤F5AKFœBKŽdBKF5M.

[r]

Somit werden dem Reaktor pro Stunde &gt;@?%AB des Stoffes

Hinweis: Ab dem 8.Mai findet die Vorlesung am Dienstag im Hertz-H¨ orsaal

[r]

[r]

und ergänzt die .nb-Unterlagen mit dem Mathematica-Befehl, um Matrizen zu potenzieren..

[r]