Kapitel 13:
Entwurf von Algorithmen
Einführung in die Informatik
Wintersemester 2007/08
Prof. Bernhard Jung
Übersicht
Einleitung: Entwurf von Algorithmen
Entwurfsprinzip: Schrittweise Verfeinerung
Entwurfsprinzip: Einsatz von Algorithmenmustern
Algorithmenmuster: Greedy
Beispiel: optimales Kommunikationsnetz
Exkurs: Listen (und Matrizen) in Python
Algorithmenmuster: Backtracking
Beispiel: Kürzeste Rundreise
Beispiel: 8-Damen-Problem
Literatur
G. Saake & K.-U. Sattler. Algorithmen und Datenstrukturen. dPunkt Lehrbuch.
2006.
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
1
Einleitung: Entwurf von Algorithmen
Programmieren ist konstruktive und kreative Tätigkeit
Trotzdem existieren verschiedene typische Muster für Algorithmen,
die in Praxis oft Anwendung finden
Erstellung eines optimalen Algorithmus i.a. nicht automatisierbar
aber fallspezifisch anzupassen sind
schon bekanntes Muster: divide-and-conquer
z.B. Algorithmenmuster für
Optimierungsprobleme, u.a.
greedy-Algorithmen
Backtracking
lokales
Optimum
globales
Optimum
effizient, liefern lokales Optimum
nicht so effizient, liefert globales Optimum
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Entwurfsprinzip: Schrittweise Verfeinerung
Beim Entwurf von Algorithmen
beschreibe Grobverfahren in abstraktem Pseudocode
Verfeinere Pseudocode und ersetze diesen nach und nach durch
detaillierten Pseudocode
dabei Zerlegung in Teilaufgaben
wiederhole
… bis letztlich Algorithmus in Programmiersprachencode beschrieben ist
Top-Down-Entwurf
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
2
Entwurfsprinzip: Schrittweise Verfeinerung
Beispiel
Grobverfahren
Einzelschritte verfeinern
1. Wasser kochen
2. Nescafe in die Tasse
3. Wasser in die Tasse
1.1 Kessel mit Wasser füllen
1.2 Auf die Herdplatte stellen
1.3 Herdplatte anstellen
1.4 Warten bis Wasser kocht
1.5 Herdplatte abstellen
2.1 Glas öffnen
2.2 Menge Kaffeepulver auf den Löffel laden
2.3 Löffel in die Tasse leeren
3.1 Kessel von der Herdplatte nehmen
3.2 Tasse mit Wasser füllen
Weiter verfeinern
…
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Entwurfsprinzip: Einsatz von Algorithmenmustern
Das (generische) Lösungsverfahren wird an einem möglichst einfachen
Vertreter der Problemklasse vorgeführt und dokumentiert
Der Entwerfer versteht die Problemlösungsstrategie und überträgt diese auf
sein Programm
Konzept moderner Softwareentwicklung: "Design Patterns"
Eine Bibliothek von Mustern ("Design Patterns", "best-practice"-Strategien) wird
genutzt, um einen abstrakten Programmrahmen zu generieren
Die freien Stellen dieses Programmrahmens werden dann problemspezifisch
ausgefüllt
In modernen Programmiersprachen wird dies z.Tl. schon weitergehend unterstützt
durch parametrisierte Algorithmen und – in objektorientierter Programmierung –
Vererbung mit Überschreiben
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
3
Algorithmenmuster Greedy
greedy = gierig
Prinzip gieriger Algorithmen:
Versuche in jedem Teilschritt so viel wie möglich zu erreichen
Beispiel
Wechselgeld (bis 1 Euro) herausgeben, mit minimaler Anzahl von Münzen à 50,
20, 10, 5, 2, und 1-Cent
Greedy-Strategie: Nimm jeweils die größte Münze unter Zielwert, und ziehe diese
von Zielwert ab
Bsp: 78 Cent -> 50 + 20 + 5 + 2 +1, d.h. 5 Münzen
Greedy berechnet bei diesem Problem immer die optimale Lösung …
… wäre anders wenn nur Münzen à 11, 5, und 1 Cent zu Verfügung stünden
z.B. 15 Cent zu wechseln
Æ Greedy: 15 = 11 + 4 • 1, d.h. 5 Münzen
Æ optimal aber: 15 = 3 • 5, d.h. 3 Münzen
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Greedy: Optimales Kommunikationsnetz
6
1
3
7
10
4
5
0
1
2
4
8
2
9
3
Aufgabe: möglichst billige Vernetzung von vorgegeben Stationen
eines Kommunikationsnetzes herstellen
Jeder Knotenpunkt soll mit jedem anderen verbunden sein, ggf. auch
auf Umweg über andere Knotenpunkte
Bekannt sind Kosten für direkte Verbindungen
Gesucht ist Teilmenge aller direkten Verbindungen, so dass
alle Knoten untereinander verbunden sind
die Gesamtkosten minimal sind (Optimierungsproblem!)
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
4
Greedy: Optimales Kommunikationsnetz
6
1
3
7
10
4
9
5
0
2
1
4
8
3
2
1. Schritt: Markiere beliebigen Knoten
2. Schritt: Betrachte alle Kanten von markierten zu unmarkierten Knoten …
im Beispiel 0
0-1 (Kosten 7), 0-2 (Kosten 1), 0-3 (Kosten 10), 0-4 (Kosten 5)
… und markiere Kante (und Zielknoten) mit geringsten Kosten
Kante 0-2, Knoten 2
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Greedy: Optimales Kommunikationsnetz
1
6
3
7
10
4
5
0
1
2
4
8
2
9
3
3. Schritt: Betrachte alle Kanten von markierten zu unmarkierten Knoten …
0-1 (Kosten 7), 0-3 (Kosten 10), 0-4 (Kosten 5)
2-1 (Kosten 2), 2-3 (Kosten 8), 2-4 (Kosten 3)
… und markiere Kante (und Zielknoten) mit geringsten Kosten
Prof. B. Jung
Æ Kante 2-1, Knoten 1
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
5
Greedy: Optimales Kommunikationsnetz
1
6
3
7
10
4
0
2
1
4
8
3
2
9
5
4. Schritt: Betrachte alle Kanten von markierten zu unmarkierten Knoten …
0-3 (Kosten 10), 0-4 (Kosten 5)
1-3 (Kosten 6), 1-4 (Kosten 4)
2-3 (Kosten 8), 2-4 (Kosten 3)
… und markiere Kante (und Zielknoten) mit geringsten Kosten
Æ Kante 2-4, Knoten 4
Prof. B. Jung
TU Bergakademie Freiberg
Einführung in die Informatik, WS 2007/08
Greedy: Optimales Kommunikationsnetz
1
0
6
3
7
10
4
5
0
1
2
4
3
3
5. Schritt: Betrachte alle Kanten von markierten zu unmarkierten Knoten …
0-3 (Kosten 10), 1-3 (Kosten 6), 2-3 (Kosten 8), 4-3 (Kosten 9)
… und markiere Kante (und Zielknoten) mit geringsten Kosten
1
4
8
2
2
9
Æ Kante 1-3, Knoten 3
Bem: markierte Knoten bilden jetzt einen "minimalen aufspannenden Baum"
(minimal spanning tree) des Graphen
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
6
Greedy: Optimales Kommunikationsnetz
Erste Variante des Algorithmus
1
[ Teilbaum R besteht anfangs aus einem beliebigem Knoten ]
while [ R noch nicht aufgespannt ]:
[ suche billigste von R ausgehende Kante ]
[ füge diese zu R hinzu ]
7
10
0
1
6
3
4 9
5
2
2
8
4
3
Verfeinerungen
while-Schleife durch for-Schleife ersetzen
da klar, dass Schleife genau (n-1)-mal durchlaufen wird:
anfangs 1 Knoten in Baum, in jedem Durchgang kommt ein Knoten hinzu
Suche der billigsten Kante
z.B. geschachtelte Schleife:
für alle Knoten a
für alle Knoten b
teste ob Kante (a,b) von R ausgeht und billiger ist bisher betrachtete Kanten
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Greedy: Optimales Kommunikationsnetz
Verfeinerte Variante des Algorithmus
1
6
[ R = beliebiger Knoten von P ]
3
7
for i = 1 … (n-1):
10
4 9
# suche billigste von R ausgehende Kante
5
0
4
minKosten = MAXKOSTEN
2
8
1
3
2
for j = 0 … (n-1):
for k = (j+1) … (n-1):
if Kante (j,k) geht von R aus and Kosten(j,k) < minKosten:
minKosten = Kosten(j,k)
billigsteKante = (j,k)
[ füge billigsteKante zu R hinzu ]
Weitere Verfeinerungen
Datenstruktur zur Darstellung von Baum festlegen
am besten wäre es, eine eigene Klasse zu definieren (objektorientierte Prog.)
als Behelf auch z.B. getrennte Speicherung von:
Prof. B. Jung
treeNodes: Liste der Knoten des Baums
treeEdges: Liste der Kanten des Baums
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
7
1
7
Greedy: Optimales Kommunikationsnetz
0
Python-Code
6
10
3
4 9
4
5
2
2
1
8
def minimalSpanningTree():
treeNodes = [0]
# initially only node 0 in tree
treeEdges = []
# ... and no edges
3
Lokale Funktion:
Nur von äußerer
Funktion
aufrufbar. Hat
Zugriff auf
lokale Variablen
der äußeren
Funktion.
def fromTreeToOutside(a,b):
if a in treeNodes and b not in treeNodes: return True
if b in treeNodes and a not in treeNodes: return True
return False
for i in range(1,SIZE):
# find cheapest edge leaving the current tree
cheapestCost = MAXCOST
for j in range(SIZE):
for k in range(j+1,SIZE):
if fromTreeToOutside(j,k) and getCost(j,k) < cheapestCost:
cheapestCost = getCost(j,k)
cheapestEdge = (j,k)
# expand the current tree
treeEdges.append( cheapestEdge )
a,b = cheapestEdge
hier nicht definiert:
if a in treeNodes: treeNodes.append(b)
getCost(j,k) – Kosten für Kante (j,k)
else: treeNodes.append(a)
SIZE – Anzahl Knoten
Prof. B. Jung
TU Bergakademie Freiberg
Einführung in die Informatik, WS 2007/08
return treeEdges
MAXCOST - z.B.1000000
Datenstruktur für Graphen:
Adjazenzmatrix (Nachbarschaftsmatrix)
Graph mit n Knoten wird durch n × n Matrix m repräsentiert
ungerichtete Graphen ohne Kantengewichte:
ungerichtete Graphen mit Kantengewichten:
bei ungerichteten Graphen ist Adjazenzmatrix symmetrisch
Kante (i,j) durch Eintag 1 in m[i][j] und m[j][i] repräsentiert
m[i][j] und m[j][i] enthalten Gewicht der Kante (i,j)
bei gerichteten Graphen i.a. unsymmetrisch
0
Prof. B. Jung
0
1
2
3
4
0
7
1
10
5
1
7
0
2
6
4
2
1
2
0
8
3
3
10
6
8
0
9
4
5
4
3
9
0
1
7
6
4
5
0
Einführung in die Informatik, WS 2007/08
3
10
1
2
4
8
2
9
3
TU Bergakademie Freiberg
8
Darstellung von Matrizen in Python
Matrix darstellbar als Liste von Listen:
jede enthaltene Liste entspricht einer Zeile der Matrix
>>>
>>>
[1,
>>>
1 2
m = [ [1,2], [3,4] ]
print m[0], m[1]
2] [3, 4]
print m[0][0], m[0][1], m[1][0], m[1][1]
3 4
Potentielle Fehlerquelle beim Erzeugen von Matrizen:
Enthaltene Listen müssen verschiedene (d.h. evtl. gleiche,
aber nicht dieselben) Objekte sein
Falls alle Teillisten dasselbe Objekt:
Veränderungen an einer Teilliste …
… wirken sich auf alle anderen aus!
nicht gewollt bei Matrizen!
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
⎡1 2⎤
⎢3 4⎥
⎣
⎦
>>> l = [1,2]
>>> m = [l,l]
>>> print m
[[1, 2], [1, 2]]
>>> l[0] = 0
>>> print l
[0, 2]
>>> print m
[[0, 2], [0, 2]]
TU Bergakademie Freiberg
Exkurs: Listen in Python
Erzeugung von Listen
>>> l1 = [2,5,9]
Explizites Aufzählen (in eckigen
Klammern)
Zahlenfolgen mit range()
"Multiplikation" von Listen mit Zahl
List comprehension
Prof. B. Jung
Generierung von Liste aus
Elementen einer andern Liste
ähnlich Def. math. Mengen,
z.B. : { i2 | i = 0..4}
auch mit Test: nur Elemente, die
Bedingung genügen, werden in
neue Liste aufgenommen
>>> l2 = range(5)
>>> l2
[0, 1, 2, 3, 4]
>>> l3 = [0] * 5
>>> l3
[0, 0, 0, 0, 0]
>>> l4 = [ i**2 for i in range(5) ]
>>> l4
[0, 1, 4, 9, 16]
>>> l5 = [ i for i in range(50)
if i%7 == 0 ]
>>> l5
[0, 7, 14, 21, 28, 35, 42, 49]
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
9
Exkurs: Listen in Python
Slice-Operator
>>> l = [1,2,3,4]
l[min:max]
Teilliste der Elemente von
Index min (einschließlich)
bis max (ausschließlich)
l[min:]
Teilliste ab Index min
(einschließlich)
l[:max]
Teilliste bis Index max
(ausschließlich)
l[:]
flache Kopie der Liste
(Listenelemente werden nicht
mit kopiert)
Prof. B. Jung
Alias
Liste wird kopiert, Elemente aber nicht
l2 = l[:]
Tiefe Kopie
anderer Name für gleiche Liste
l1 = l
Flache Kopie
auch Listenelemente werden kopiert
Modul copy
l3 = deepcopy(l)
Unterschiedl. Verhalten bei
Hinzufügen oder Entfernen von
Elementen der Original-Liste
Ändern von Elementen der
Originalliste
Prof. B. Jung
>>> l[1:]
[2, 3, 4]
>>> l[:2]
[1, 2]
>>> l[:]
[1,2,3,4]
Einführung in die Informatik, WS 2007/08
Exkurs: Listen in Python
Flache und tiefe Kopien
>>> l[1:4]
[2, 3, 4]
>>>
>>>
>>>
>>>
>>>
TU Bergakademie Freiberg
l = [ [1,2], [3,4] ]
l1 = l # Alias für l
l2 = l[:] # flache Kopie
from copy import deepcopy
l3 = deepcopy(l)
>>> l.append([5,6])
>>> l1
[[1, 2], [3, 4], [5, 6]]
>>> l2
[[1, 2], [3, 4]]
>>> l3
[[1, 2], [3, 4]]
>>> l[0][0] = 100
>>> l1
[[100, 2], [3, 4], [5, 6]]
>>> l2
[[100, 2], [3, 4]]
>>> l3
[[1, 2], [3, 4]]
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
10
Erzeugen von n×n Matrizen in Python
Falsch:
Richtig:
>>> def makeMatrixBuggy(n):
return [ [0]*n ] * n
>>> def makeMatrix(n):
return [ [0]*n for i in range(n) ]
>>> m1 = makeMatrixBuggy(2)
>>> m1
[[0, 0], [0, 0]]
>>> m1[0]
[0, 0]
>>> m1[0][0]
0
>>> m1[0][0] = 1
>>> m1
[[1, 0], [1, 0]]
>>> m2 = makeMatrix(2)
>>> m2
[[0, 0], [0, 0]]
>>> m2[0]
[0, 0]
>>> m2[0][0]
0
>>> m2[0][0] = 1
>>> m2
[[1, 0], [0, 0]]
erzeugt Liste, deren n Elemente
jeweils dieselbe Liste sind
erzeugt Liste, deren n Elemente zwar
gleich, aber nicht dieselbe Liste sind
Kopieren so erzeugter Matrizen i.d.R. mit deepcopy()!
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Greedy: Optimales Kommunikationsnetz
Analyse
[ R = beliebiger Knoten von P ]
for i = 1 … (n-1):
# suche billigste von R ausgehende Kante
minKosten = MAXKOSTEN
for j = 0 … (n-1):
for k = (j+1) … (n-1):
if Kante (j,k) geht von R aus and Kosten(j,k) < minCosts:
minKosten = Kosten(j,k)
billigsteKante = (j,k)
[ füge billigsteKante zu R hinzu ]
Laufzeit: proportional zu n3
Begründung: drei geschachtelte for-Schleifen,
die jeweils ungefähr n-mal durchlaufen werden
Verbesserung möglich, so dass Laufzeit proportional zu n2
Algorithmus findet immer (global) optimale Lösung
Algorithmus von Prim
i.a. finden greedy-Algorithmen nur lokales Optimum
bei betrachtetem Problem gilt aber: lokales Optimum = globales Optimum
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
11
Wo Greedy fehlschlägt:
Kürzeste Rundreise
Gesucht: Rundreise durch alle Knoten, so dass
jeder Knoten genau einmal besucht wird
Rundreise am selben Knoten beginnt und endet
Kosten minimal sind
1
7
6
3
10
4
5
0
1
2
4
8
2
9
3
Greedy-Strategie:
beginne bei beliebigem Knoten
gehe vom aktuellen Knoten zu dem unbesuchten Nachbarknoten mit geringsten
Pfadkosten
wiederhole, bis alle Knoten besucht
gehe zurück zum Ausgangsknoten
liefert im Beispiel z.B. Rundreise: 0 Æ 2 Æ 1 Æ 4 Æ 3 Æ 0 (Kosten 26)
kürzere Rundreise z.B.: 0 Æ 2 Æ 1 Æ 3 Æ 4 Æ 0 (Kosten 23)
optimale Lösung kann z.B. mit Backtracking gefunden werden …
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Algorithmenmuster Backtracking
Backtracking ist wichtiges Algorithmenmuster für Such- und
Optimierungsprobleme
Backtracking realisiert eine allgemeine, systematische Suchtechnik
Typische Anwendungsgebiete: Planungsprobleme (Routen- u. Tourenplanung),
Konfigurierungen (z.B. VLSI-Layout), Optimierungen, Spielprogramme (Schach,
Dame, …), …
Lösungsraum kann vollständig betrachtet werden
Vorgehen nach Versuch-und-Irrtum-Prinzip (trial-and-error)
versucht, schrittweise eine Teillösung zu Lösung auszubauen
dabei systematisches Ausprobieren alternativer Lösungswege
Beispiel: Maus und Käse
durch "Backtracking" zu früheren Entscheidungspunkten
Backtracking wird i.d.R. durch Rekursion implementiert
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
12
Backtracking: Finden in einem Labyrinth
Jeder Weg (Konfiguration) kann mit einem Folgeschritt zu einem
verlängerten Weg (Folgekonfiguration) erweitert werden
Für jeden Weg (Konfiguration) ist entscheidbar, ob er eine Lösung ("Käse
gefunden") oder keine Lösung ("Sackgasse" oder "Käse nicht gefunden") ist
In der Sackgasse sucht die Maus keinen Folgeweg, sondern kehrt um zur
vorherigen Konfiguration (Backtracking) zurück und sucht dort weiter
Das wiederholte Absuchen desselben Folgeweges muss verhindert werden
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Prinzip des Backtracking
Prolemlösungsverfahren betrachtet zunächst Start-Konfiguration
Für jede Konfiguration (Zustand) können i.a. mehrere Nachfolge-Konfigurationen
(Zustände) erzeugt werden
Für jede Konfiguration (Zustand) ist entscheidbar, ob es sich um eine Lösung handelt
i.a. wird jede dieser Nachfolgekonfigurationen überprüft
Backtracking-Muster:
procedure backtrack(K: Konfiguration):
if [K ist Lösung]:
gib K aus
else:
for each [ direkte Erweiterung K' von K ]:
backtrack( K' )
Aufruf von
backtrack() mit
Start-Konfiguration
Backtracking terminiert garantiert, wenn
nur endlich viele Konfigurationen bestehen
jede Konfiguration höchstens einmal gestestet wird
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
13
Backtracking: Kürzeste Rundreise, bzw.
Travelling salesman problem (tsp)
1
7
3
10
0
Backtracking-Muster:
1
procedure backtrack(K: Konfiguration):
if [K ist Lösung]:
gib K aus
else:
for each [ direkte Erweiterung K' von K ]:
backtrack( K' )
6
4
5
2
4
8
2
9
3
Traveling Salesman Problem: finde kürzeste Rundreise durch n Städte (jede Stadt
darf nur einmal besucht werden, außer Start- = Zielort)
Anpassung des Musters für Traveling Salesman Problem:
procedure tsp( trip ):
if [trip besucht alle Städte]:
[erweitere trip um Heimreise zum Ausgangsort]
[gib trip und Kosten dafür aus]
else:
for each [bislang unbesuchte Stadt s]:
[ trip' = trip erweitert um Reise nach s]
Prof. B. Jung
TU Bergakademie Freiberg
Einführung in die Informatik, WS 2007/08
tsp( trip' )
Backtracking: Travelling salesman problem (tsp)
Umsetzung in Python
def tsp(trip):
# solution found
if len(trip) == SIZE:
roundtrip = trip + [ trip[0] ] # go home
print "Roundtrip", roundtrip, "costs", getPathCost(roundtrip)
# expand trip, try all unvisited cities
else:
for i in range(SIZE):
if i not in trip:
tsp( trip + [i])
return
# Hauptprogramm
if __name__ == '__main__':
tsp([0]) # start trip in city 0
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
14
Backtracking: Travelling salesman, Testlauf u. Analyse
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Roundtrip
Prof. B. Jung
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
[0,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
4,
4,
4,
4,
4,
4,
2,
2,
3,
3,
4,
4,
1,
1,
3,
3,
4,
4,
1,
1,
2,
2,
4,
4,
1,
1,
2,
2,
3,
3,
3,
4,
2,
4,
2,
3,
3,
4,
1,
4,
1,
3,
2,
4,
1,
4,
1,
2,
2,
3,
1,
3,
1,
2,
4, 0] costs 31
3, 0] costs 30
4, 0] costs 28
2, 0] costs 25
3, 0] costs 31
2, 0] costs 29
4, 0] costs 23
3, 0] costs 26
4, 0] costs 24
1, 0] costs 29
3, 0] costs 23
1, 0] costs 25
4, 0] costs 25
2, 0] costs 23
4, 0] costs 29
1, 0] costs 31
2, 0] costs 26
Æ
1, 0] costs 30
3, 0] costs 29
Æ
2, 0] costs 24
3, 0] costs 25
Æ
1, 0] costs 28
2, 0] costs 23
1,
0] costs
31 WS 2007/08
Einführung
in die Informatik,
1
7
0
6
10
3
4 9
4
5
2
2
1
8
3
Es werden 24 Rundreisen
gefunden
minimale Kosten (per
Inspektion der Ergebnisse): 23
jede Rundreise entspricht
einer Permutation der Zahlen
1..4
Für n Objekte gibt es n!
Permutationen
24 = 4!
Laufzeit des Algorithmus
proportional zu (n-1)!
damit nur für kleine n effektiv
ausführbar
(mit Code-Optimierungen z.B.
n = 40 – 60)
TU Bergakademie Freiberg
Backtracking: Das Achtdamen-Problem
Das Damenproblem (8−Queens−Problem):
Man finde eine Stellung für acht Damen auf einem Schachbrett, so dass keine
zwei Damen sich gegenseitig schlagen können
In Informatik auch auf n-Damenproblem erweitert (Platzierung von n Damen
auf n × n Brett)
Zwei Lösungen des Achtdamen-Problems
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
15
Backtracking: Das Achtdamen-Problem
Vorgangsweise
von oben nach unten, je1 Dame in Zeile setzen
(gleiche Zeile ausgeschlossen)
dabei werden jeweils alle unbedrohten Felder der Zeile ausprobiert
Lösung gefunden, wenn 8. Dame auf unbedrohtem Feld platziert wird
def PLATZIERE(i): # platziere Dame in i-ter Zeile
for h = 1 .. 8: # alle Spalten h ausprobieren
if [Feld in Zeile i, Spalte h nicht bedroht]:
[setze Dame auf dieses Feld (i,h)]
if [Brett voll]:
# d.h. i == 8
[Gib Konfiguration aus]
else:
PLATZIERE(i+1)
Prof. B. Jung
TU Bergakademie Freiberg
Einführung in die Informatik, WS 2007/08
Konfigurations- bzw. Suchraum
für 4-Damenproblem
D
D
D
D
D
D
…
D
D
D
…
D
…
[symmetrisch zu
Teilbaum links]
D
D
D
D
D
D
def PLATZIERE(i): # platziere Dame in i-ter Zeile
for h = 1 .. 8: # alle Spalten h ausprobieren
if [Feld in Zeile i, Spalte h nicht bedroht]:
[setze Dame auf dieses Feld (i,h)]
D
if [Brett voll]: # d.h. i == 8
[Gib Konfiguration aus]
else:
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
PLATZIERE(i+1)
D
D
Lösung!
D
TU Bergakademie Freiberg
16
Backtracking: Das Achtdamen-Problem
Gegenseitige Bedrohung von 2 Damen, falls:
• gleiche Zeile (ausgeschlossen durch Algorithmus)
• gleiche Spalte
• gleiche Diagonale
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
def bedroht( (x1,y1), (x2,y2) ):
if x1 == x2: return True
if y1 == y2: return True
if x1+y1 == x2+y2: return True
if x1-y1 == x2-y2: return True
return False
#
#
#
#
gleiche
gleiche
gleiche
gleiche
TU Bergakademie Freiberg
Spalte
Reihe
Diagonale (aufwaerts)
Diagonale (abwaerts)
def istBedroht( (x,y), andere):
# ist Feld bedroht?
for xi,yi in andere:
if bedroht( (xi,yi), (x,y) ): return True
return False
def platziereNaechsteDame( bisher ):
zeile = len(bisher) + 1
for spalte in range(1,9):
if not istBedroht( (zeile,spalte), bisher):
jetzt = bisher + [ (zeile,spalte) ]
if len(jetzt)==8:
print "Loesung", jetzt
else:
platziereNaechsteDame(jetzt)
# Hauptprogramm
if __name__ == "__main__":
platziereNaechsteDame([])
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
17
Backtracking: Das Achtdamen-Problem
Anzahl der Lösungen steigt mit der Brettgröße sehr stark an!
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
Backtracking: Sudoku
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
18
Zusammenfassung
Betrachtete Algorithmenmuster
greedy
backtracking
berechnet lokales Optimum
polynomiale Zeitkomplexität
berechnet globales Optimum
Zeitkomplexität entsprechend Größe des (problemspezifischen) Konfigurationsraums,
z.B. exponentiell (proportional 2n) oder auch – noch schlimmer – proportional zu n!
vollständiges Durchsuchen des Konfigurationsraums per Backtracking daher nur für
kleinere Probleminstanzen praktisch durchführbar
bei großen Probleminstanzen muss man sich evtl. mit lokalen Optima begnügen,
z.B. per Greedy-Algorithmus berechnet
Weitere Algorithmenmuster
divide-and-conquer (vgl. Kapitel 11: Suche)
dynamisches Programmieren (Literatur)
…
Prof. B. Jung
Einführung in die Informatik, WS 2007/08
TU Bergakademie Freiberg
19