Musterlösung

Werbung
Prof. Dr. Dennis Hofheinz
Lukas Barth, Lisa Kohl
K a r l s ru h e r I n s t i t u t f ü r T e c h n o l o g i e
Institut für Theoretische Informatik
9. Übungsblatt zu Algorithmen I im SoSe 2016
https://crypto.iti.kit.edu/index.php?id=algo-sose16
{lisa.kohl,lukas.barth}@kit.edu
Musterlösungen
Aufgabe 1
(Dijkstra, 4 Punkte)
Wir beschäftigen uns mit dem Algorithmus von Dijkstra aus der Vorlesung. Sei ein Graph G = (V, E)
wie unten dargestellt. Führen Sie Dijkstras Algorithmus auf G aus. Sie können die Darstellung von
G benutzen, um die Ergebnisse nach der Ausführung darin einzutragen. Schreiben Sie dazu in jeden
Knoten v ∈ V rechts vom Doppelpunkt die Länge des kürzesten Pfads vom Startknoten s aus gesehen
und links vom Doppelpunkt den Vorgänger auf diesem kürzesten Pfad. Zeichnen Sie den Baum der
kürzesten Wege von s zu allen anderen Knoten aus V in G ein. Geben Sie die Reihenfolge der Knoten an,
in der sie als scanned markiert werden. Geben Sie außerdem für jeden Knoten v ∈ V alle Zwischenwerte
d[v] und parent[v] an, die während Ausführung des Algorithmus angenommen werden.
Darstellung von G:
a
10
s
:
:
3
1
5
5
1
1
3
c
7
b
3
d
:
:
:
2
6
6e
1
2
f
e
:
1
:
Musterlösung:
Die Knoten werden in der Reihenfolge s, d, c, e, f, b, a als scanned markiert. Weiter gilt für die Werte
von d und parent:
• d[s] = 0 und parent[s] = s während der gesamten Ausführung
• d[a] = ∞ und parent[s] = ⊥ nach Initialisierung, d[a] = 10 und parent[s] = s nach Relaxieren der
von s ausgehenden Kanten, d[a] = 9 und parent[s] = c nach Relaxieren der von c ausgehenden
Kanten und schließlich d[a] = 8 und parent[s] = b nach Relaxieren der von b ausgehenden Kanten
• d[b] = ∞, 11, 7 und parent[b] = ⊥, c, e
1
• d[c] = ∞, 5, 4 und parent[b] = ⊥, s, d
• d[d] = ∞, 1 und parent[b] = ⊥, s
• d[e] = ∞, 7, 5 und parent[b] = ⊥, d, c
• d[f ] = ∞, 7, 6 und parent[b] = ⊥, d, e
a
10
s
b:8
3
1
s:0
5
5
1
3
1
c
7
3
b
d
d:4
e:7
s:1
2
6
6e
1
2
f
e
c:5
Aufgabe 2
1
e:6
(Unzuverlässige Kommunikation, 4 Punkte)
Sie sind Administrator eines Computernetzwerks bestehend aus n Rechnern und Netzwerkverbindungen
zwischen diesen. Leider sind die Netzwerkverbindungen nicht absolut zuverlässig: Jede Verbindung
zwischen zwei Rechnern a und b hat eine Wahrscheinlichkeit 0 < p(a,b) < 1, dass ein auf dieser
Verbindung gesendetes Paket nicht ankommt. Die Verbindungen sind gerichtet, das heißt es kann sein,
dass p(a,b) 6= p(b,a) gilt.
Ihre Aufgabe ist es nun, zwischen zwei gegebenen Rechnern einen möglichst zuverlässigen Pfad zu finden.
Geben Sie hierfür einen möglichst effizienten Algorithmus an, und begründen Sie kurz, warum dieser
funktioniert.
Musterlösung:
Das Problem wird natürlich als Graph modelliert: Hier stehen Knoten für Rechner und Kanten für
Verbindungen zwischen Rechnern. Die Kantengewichte c : E → (0, 1) symbolisieren dabei die Wahrscheinlichkeit, dass ein Paket auf der entsprechenden Kante erfolgreich versendet wird, also c((a, b)) = 1 − p(a,b) .
Sei nun ein Startrechner S und ein Zielrechner T gegeben. Wir führen einen modifizierten Algorithmus
von Dijkstra aus: Die vorläufigen Distanzen d[v] stehen nun für die Zuverlässigkeit des vorläufig besten
gefundenen Pfades von S nach v und werden mit 0 (statt mit ∞) initialisiert (Ausnahme: d[S] = 1). Das
parent-Feld funktioniert wie in Dijkstras Algorithmus und speichert den Vorgänger im vorläufig besten
Pfad. Eine Kante (u, v) wird relaxiert, indem die vorläufige Zuverlässigkeit von S nach u mit c((u, v))
multipliziert wird, und die vorläufige Zuverlässigkeit von S nach v (zusammen mit dem parent-Zeiger)
aktualisiert wird, falls ein besserer Pfad gefunden wurde, also:
d[v] = max{d[v], d[u] · c((u, v))}
2
Die Prioritätswarteschlange ist in unserem Fall ein Max-Heap, der die vorläufige Zuverlässigkeit d[v] als
Schlüssel verwendet.
Der Korrektheitsbeweis funktioniert analog zu Dijkstras Algoritmus: Zunächst ist es wichtig zu sehen,
dass in dem Moment, in dem ein Knoten v aus der Prioritätswarteschlange entfernt wird, kein Pfad mit
höherer Zuverlässigkeit als d[v] von S nach v mehr existieren kann.
Wir beweisen dies mittels Induktion über die Länge des optmialen S − v-Pfades: Für Länge 1 ist die
Behauptung trivialerweise wahr: Der Pfad besteht nur aus S, d[S] = 1, und besser wird es nicht. Gelte
nun also die Behauptung für eine beliebige, aber feste Pfadlänge l. Sei der Pfad P = hS, . . . , u, vi ein
optimaler S − v-Pfad der Länge l + 1. Wenn zu dem Zeitpunkt, zu dem v aus dem Heap genommen wird,
parent[v] = u gilt, dann ist d[v] per Definition optimal. Angenommen also, dass parent[v] = w 6= u gilt,
und dass d[v] = d[w] · c((w, v)) < d[u] · c((u, v)). Wir wissen, dass die Länge des optimalen S − u-Pfades
P 0 = hS, . . . ui hier l ist (da P eine Länge von l + 1 hat). Nach Induktionsvorraussetzung wurde also d[u]
korrekt berechnet, und insbesondere muss d[u] > d[v] gelten. Damit wurde aber u bereits vor v aus dem
Max-Heap entfernt, die Kante (u, v) wurde relaxiert und d[v] wurde korrekterweise auf d[u] · c((u, v))
gesetzt. Somit kann d[v] > d[u] · c((u, v)) nicht mehr gelten.
Mit dieser Einsicht ist es einfach, die Korrektheit des gesamten Algorithmus zu sehen: Für jeden Knoten
v gilt, dass falls es überhaupt einen S − v-Pfad gibt, v irgendwann in den Max-Heap eingefügt, und
somit v auch irgendwann aus dem Max-Heap entfernt wird. Damit wird der optimale Pfad zu jedem
von S erreichbaren Knoten errechnet. Für alle nicht erreichbaren Knoten bleibt d[v] = 0 gesetzt, was
die Nichterreichbarkeit korrekt abbildet.
Das Finden eines optimalen S − T -Pfades beschränkt sich danach darauf, die parent-Einträge korrekt
von T zu S zurückzuverfolgen.
Aufgabe 3
(Verbesserter Bellman-Ford-Algorithmus, 1 + 4 Punkte)
Gegeben sei folgende Verbesserung des Bellman-Ford-Algorithmus: Im gerichteten Graphen G = (V, E)
weisen wir zunächst den Knoten eine beliebige aber feste Ordnung zu. Die Knoten seien nun V =
hv1 , v2 , v3 , . . . vn i. Nun können wir E in zwei Teile Ef ∪ Eb = E aufteilen, sodass Ef := {(vi , vj ) ∈ E |
i < j} und Eb := {(vi , vj ) ∈ E | i > j} gilt. Intuitiv enthält Ef also alle Kanten, die von einem kleineren
auf einen größeren Knoten zeigen (Eb entsprechend umgekehrt).
Weiterhin sei folgende Änderung des Bellman-Ford-Algorithmus gegeben: Anstatt in jedem der n
Durchläufe alle Kanten in irgendeiner Reihenfolge zu relaxieren, gehen wir in jedem Durchlauf wie folgt
vor: Wir betrachten die Knoten in der Reihenfolge v1 , v2 , v3 , . . . vn und relaxieren dabei für jeden Knoten
alle Kanten in Ef , die den Knoten verlassen. Danach betrachten wir alle Knoten in der Reihenfolge
vn , vn−1 , . . . v1 und relaxieren dabei für jeden Knoten alle Kanten in Eb , die den Knoten verlassen.
a) Zeigen Sie: Gf = (V, Ef ) und Gb = (V, Eb ) sind jeweils DAGs.
b) Zeigen Sie: Die veränderte Version des Bellman-Ford-Algorithmus berechnet bereits nach dn/2e
Schritten das Ergebnis, d.h. einen kürzesten s − t-Pfad oder (mindestens) einen negativen Kreis.
Tipp: Überlegen Sie sich, was der Algorithmus auf den folgenden zwei Graphen tut. Diese beiden
Graphen sind nur als Hilfestellung angegeben. Zur Lösung dieser Aufgabe ist es
nicht erforderlich, dass Sie den Algorithmus auf ihnen ausführen. Es hilft Ihnen aber
hoffentlich.
(a) Ein einfacher Pfadgraph: V = {1, 2, . . . n}, E = {(i, i + 1) | i ∈ {1, 2 . . . n − 1}}
(b) Zwei aufeinander zulaufende Pfadgraphen:
V = {1, 2, . . . n}
E = {(i, i + 1) | i ∈ {1, 2 . . . d
n
n
− 1e}} ∪ {(i + 1, i) | i ∈ {d − 1e . . . n − 1, n}}
2
2
3
Musterlösung:
Zunächst sei angemerkt, dass diese Variante von Bellman-Ford bekannt ist als Yen’s Improvement on
Bellman-Ford.
a) Angenommen, es gäbe einen Kreis in Gf . Wir laufen (n + 1) Schritte in diesem Kreis und schreiben
die Indizes der hierbei gesehenen Knoten als Folge auf. Da alle Kanten in Gf von einem kleineren
auf einen größeren Index zeigen, muss diese Folge streng monoton steigend sein. In Gf gibt es
aber nur n Knoten, und somit nur n verschiedene Knotenindizes. Dies ist ein Widerspruch. Der
Beweis für Gb funktioniert analog.
b) Sei P = hS, . . . T i ein optimaler S − T -Pfad. Jede Kante in P liegt entweder in Ef oder in Eb . Die
Idee ist nun, P in (maximale) Teilpfade zu zerlegen, die jeweils vollständig in Gf bzw. Gb liegen:
O.b.d.A. gehen wir davon aus, dass die erste Kante von P in Ef und die letzte Kante von P in
→
←
→
←
→
←
Eb liegt. Dann lässt sich P schreiben als eine Folge von Teilpfaden hP1 , P1 , P2 , P2 , . . . , Pk , Pk i,
→
←
wobei alle Pi in Gf , und alle Pi in Gb liegen. Es ist einfach zu sehen, dass k ≤
→ ←
(Pi , Pi )
Paar
enthalten.
n
2
gelten muss: Ein
enthält immer mindestens zwei Kanten, und P kann insgesamt maximal n Kanten
Wir zeigen nun, dass i Iterationen des veränderten Bellman-Ford-Algorithmus ausreichend sind,
→ ←
um den Teilpfad von P bis hS, . . . Pi , Pi i korrekt zu finden. Damit ist klar, dass nach k Iterationen
P korrekt gefunden wurde. Dies zeigen wir induktiv: Für i = 0 ist die Behauptung trivial wahr:
→ ←
Der Teilpfad von P mit 0 (Pi , Pi )-Paaren besteht nur aus S. Sei nun also i beliebig aber fest,
→ ←
und der Pfad P 0 = hS, . . . Pi , Pi i somit korrekt gefunden. In der ersten Hälfte von Iteration
i + 1 betrachten wir nun die Knoten in Reihenfolge aufsteigender Indizes und relaxieren ihre
→
ausgehenden Kanten in Ef . Damit werden alle Kanten in Pi+1 in der Reihenfolge, in der sie in
→
→
Pi+1 auftreten, relaxiert, und somit wird P 0 um Pi+1 erweitert. In der zweiten Hälfte betrachten
wir alles Knoten in umgekehrter Indexreihenfolge und relaxieren die eingehenden Kanten in Eb .
←
←
Damit werden nun alle Kanten in Pi+1 in der korrekter Reihenfolge relaxiert, und P 0 um Pi+1
→
←
erweitert. Am Ende von Iteration i + 1 wurde der Pfad P 00 = hS, . . . Pi+1 , Pi+1 i korrekt gefunden.
Die Erkennung von negativen Kreisen funktioniert analog zum unveränderten Bellman-FordAlgorithmus: Sollte sich nach k Schritten noch eine vorläufige Distanz verändern, so liegt ein
negativer Kreis vor.
Aufgabe 4
(Doktor Meta, 6 Punkte)
Als der ebenso orientierungsschwache wie unermüdliche Untersuperbösewicht Røbøt endlich in Doktor
Metas geheimer Basis ankommt, ist Doktor Meta über die Verspätung und die übrige Ausbeute von
1-Cent-Stücken alles andere als erfreut. Um ihn in bessere Laune zu versetzen, erzählt Røbøt von den
Begegnungen mit verschiedenen Bösewichten auf seinen Irrwegen durch das Tunnelsystem.
Ein Superbösewicht hat genug von unzuverlässigen elektronischen Gehilfen und bietet deshalb eine große
Menge von identischen Bauteilen vom Typ A für eine Preis von 1, 25 Euro pro Bauteil zum Verkauf
an. Ein Mittelbösewicht hat den Plan ein Roboterheer aufzubauen noch nicht aufgegeben hat und ist
verzweifelt auf der Suche nach Bauteilen von Typ A. Er ist bereit je zwei Bauteile vom Typ A für je drei
Bauteile vom Typ B, die er selbst noch übrig hat, zu tauschen. Ein vom gleichen Bausatz stammende
und ähnlich fehlkonstruierte Unterbösewicht hat sich ebenso mit einer Menge Geld im Gepäck verlaufen.
Sein Plan ist es einen Unterbösewichtsgehilfen zu bauen, der den Weg für ihn findet. Dazu möchte er
Bauteile vom Typ B zum Preis von 0, 875 Euro pro Bauteil erwerben.
Plötzlich ist Doktor Meta nicht mehr schlecht gelaunt, er rechnet nach, dass er so einen Euro ganz
einfach in 1, 05 Euro verwandeln kann. Damit Røbøt beim nächsten Mal eine solche Gelegenheit von
selbst erkennt, möchte Doktor Meta einen geeigneten Algorithmus entwerfen.
4
Seien dazu Allgemein eine Menge von angebotenen Objekten a1 , . . . , an (im vorliegenden Fall Euros,
Bauteile vom Typ A und Bauteile vom Typ B) gegeben und weiter eine Tabelle T , wobei T [i, j] jeweils
angibt wieviele Einheiten von Objekt aj für ein Objekt ai angeboten werden.
Im vorliegenden Fall ergibt sich also T [1, 2] = 0, 8, T [2, 3] = 1, 5 und T [3, 1] = 0, 875 und damit
T [1, 2] · T [2, 3] · T [3, 1] = 1, 05 > 1.
Modellieren Sie das Problem mit Hilfe von einem geeigneten Graphen und konstruieren Sie einen
effizienten Algorithmus, der entscheidet ob es eine Folge von Objekten ai1 , . . . , aik gibt, sodass T [i1 , i2 ] ·
T [i2 , i3 ] · · · T [ik , i1 ] > 1. Analysieren Sie die Laufzeit Ihres Algorithmus.
Musterlösung:
Wir möchten das Problem mit Hilfe des Bellman-Ford-Algorithmus lösen. Dazu modellieren wir jeden
Typ von Objekten (also Euros und Bauteilen) als einen Knoten des Graphen G = (V, E), und jede
Tauschmöglichkeit zwischen zwei Typen von Objekten als eine Kante zwischen den entsprechenden
Knoten. Würden wir die „Tauschkurse“ zwischen den Objekten direkt als Kantengewichte verwenden,
müssten wir nun einen positiven Kreis finden, was Bellman-Ford nicht kann.
Wir beobachten aber, dass
T [i1 , i2 ] · T [i2 , i3 ] · · · · T [ik , i1 ] > 1
gleichbedeutend ist zu
1
1
1
·
··· ·
<1
T [i1 , i2 ] T [i2 , i3 ]
T [ik , i1 ]
Wenn wir nun beide Seiten logarithmieren ergibt sich
log
1
1
1
+ log
· · · + log
<0
T [i1 , i2 ]
T [i2 , i3 ]
T [ik , i1 ]
Wir definieren daher das Kantengewicht c : E → R als c((ij , ik )) = log T [ij1,ik ] = − log T [ij , ik ]. Ein
Kreis mit negativem Gewicht in diesem Graphen entspricht einer gesuchten Folge von Objekttypen, mit
der sich Gewinn durch „Im-Kreis-Tauschen“ erzielen lässt.
Fraglich ist noch, von welchem Knoten aus Bellman-Ford gestartet werden muss. Es ist nicht klar, dass
ein Knoten existieren muss, von dem aus ein Pfad zu jedem negativen Kreis existiert. Daher fügen wir
einen weiteren Knoten v0 und Kanten (v0 , vi ) für alle vi ∈ V hinzu, und setzen c((v0 , vi )) = 0 für alle
vi ∈ V . Wir starten Bellman-Ford auf v0 .
Sei n die Anzahl der Arten Objekten, dann
hat G n Knoten und bis zu n2 Kanten. Die Zeitkomplexität
3
von Bellman-Ford liegt dann in O n .
5
Herunterladen