ETH Zürich Institut für Theoretische Informatik Prof. Dr. Angelika Steger WS 2005/06 Musterlösung zur Klausur Musterlösung zur Klausur “Algorithmen und Komplexität” - WS 05/06 Die vorliegende Version der Musterlösung wurde von Mattia Bergomi ([email protected]) der Vorlesung Algorithmen und Komplexität im WS 2006/07 bearbeitet. Aufgabe 1 log(n) (a) Ja, weil lim sup n log(n) = lim sup n = lim sup n1 = 0 < ∞ (letzten Schritt mit De l’Hôpital). 2 n n→∞ n→∞ n→∞ (b) Nein: Q UICK S ORT benötigt im Durchschnitt Laufzeit Θ (n log(n)), aber im schlimmsten Fall Ω n2 . (c) Nein: wir haben gesehen, dass mit Hilfe von Union-Find Strukturen ergibt sich dann eine Laufzeit von O (m log(n)). (d) Nein, Beweis durch Widerspruch: Angenommen, es existiert einen auf Vergleichen basierenden Suchbaum, der die Operationen I NSERT und E XTRACT M IN in amortisierter Zeit O (1) ausführt. Dann können wir ein Sortieralgorithmus wie folgt konstruieren: • Zuerst rufen wir n mal die Operation I NSERT auf. • Dann rufen wir n mal die Operation E XTRACT M IN auf, wobei wir die extrahierte Objekte in einem Array sukzessiv speichern. • Am Ende ist dann dieses Array offenbar das gesuchte Ergebnis. Die Amortisierte Laufzeit (a) ist eine obere Schranke für die tatsächliche Kosten (t) einer Sequenz von k Operationen, d.h. a(i) ≥ t(k). Somit benötigt unserer Sortieralgorithmus n · O (1) sowohl für die I NSERT-Phase als auch für die E XTRACT M IN-Phase, also insgesamt O (n). Das steht aber im Widerspruch zum Satz 2.4 aus der Vorlesung: “Jeder Algorithmus, der n Elemente mit Hilfe von “if”-Abfragen sortiert, benötigt mindestens Ω (n log(n)) Vergleiche”. Als Erinnerung schreiben wir hier ein Resultat aus Kapitel 4.4 aus der Vorlesung, das mit der Behauptung dieser Aufgabe auch zu tun hat: Feld oder Liste (Sortiert) Feld oder Liste (unsortiert) SuchBaum I NSERT E XTRACT M IN O (n) O (1) O (log(n)) O (1) O (n) O (log(n)) D ECREASE K EY O (n) O (1) O (log(n)) 1 Aufgabe 2 (a) Wir verwenden den Algorithmus von Kruskal: “Starte mit einem leeren Graph und addiere sukzessiv die kleinste Kante, nur falls der Graph kreisfrei bleibt. Am Ende ist der resultierende Graph ein minimaler Spannbaum”. 12 9 6 2 4 1 11 5 7 4 1 11 12 4 1 11 5 7 4 1 11 5 4 8 7 3 11 4 8 5 10 6 5 6 7 3 11 1 10 12 9 2 7 3 10 12 9 2 8 3 10 6 2 8 1 11 12 9 7 3 10 6 2 4 8 5 10 9 7 3 5 6 2 8 3 12 9 6 2 8 12 9 Bem: Da die Gewichte alle paarweise verschieden sind, ist der minimale Spannbaum eindeutig (für den Beweis dieses Satzes siehe die Musterlösung von ”Aufgabe 5e - Klausur von WS 2004/05”). 1 10 (b) 1. Ja, z.B. mit Kruskal berechnet, wo e die erste betrachtete Kante ist. 2. Nein, betrachte das folgende Gegenbeispiel: 1 1 e 1 Aufgabe 3 (a) Der Graph G ist partitionierbar in 2 Cliquen :⇔ Es existieren 2 Knotenmengen V1 und V2 (mit V1 ∪ V2 = V, V1 ∩ V2 = ∅) so, dass alle Knoten in Vi vollständig miteinander verbunden sind. Die Idee ist 2-C LIQUEN -PARTITION zu 2-C OL zu reduzieren (d.h. zeige: 2-C LIQUEN -PARTITION ≤p 2-C OL). Geht man zum Komplementgraph über (d.h. alle Knoten zu verbinden, die vorher nicht verbunden waren, und alle ursprüngliche Kanten zu löschen), so sucht man jetzt 2 “Anti-Cliquen” (d.h. Knotenmengen ohne eine einzige Kante zwischen den Knoten), die den ganzen Graph überdecken. Wenn es aber 2 solche Knotenmenge gibt, dann lässt sich der Graph mit 2 Farben färben, ansonsten nicht. Das 2-Färbbarkeitsproblem 2-C OL ist bekanntlich (und klarerweise) polynomiell lösbar und somit, nach der Reduktion, auch 2-C LIQUEN -PARTITION. (b) Ganz analog wie beim Teil (a), aber hier zeigen wir 3-C OL ≤p 3-C LIQUEN -PARTITION. 3-C OL ist bekanntlich (Satz 5.10 im Skript) N P-vollständig (und offenbar k-C LIQUEN -PARTITION ∈ N P, da jede vorgegebene Lösung in polynomieller Zeit prüfbar ist). 2 Aufgabe 4 (a) In den Zeilen 4-8 wird die Variable d die Summe der Grade aller Knoten, und dann am Ende (Zeile 9) durch n dividiert, somit am Ende ist es: deg(v) 2|E| d = v∈V = n |V | (b) Zur Erinnerung: für einen Graph G = (V, E) gilt: Speicher Bedarf e ∈ E? Finde alle Γ(v) Adjazenz-Matrix Θ |V |2 O (1) Θ (|V |) Adjazenz-Liste Θ (|V | + |E|) O (min{deg(u), deg(v)}) Θ (deg(v)) Die Laufzeit ist von den 2 For-Schleifen gegeben (mit Konst. Anzahl von Operationen), also für eine Adjazenzliste ergibt sich: deg(v) = Θ (2|E|) = Θ (|E|) Θ (deg(v1 )) + . . . + Θ (deg(vn )) = Θ v∈V Für eine Adjazenzmatrix ist: Θ (|V |) + . . . + Θ (|V |) = Θ (|V | · |V |) = Θ |V |2 Aufgabe 5 Wie man leicht sehen kann, alle Werte können in einer (N + 1) × (K + 1) Matrix A gespeichert werden (wobei A0,· = 1 = A·,0 nach Randbedingungen). Jeder Wert hängt nur vom “obigen” und “linken oben” Werte ab, somit können wir zuerst alle Werte einer Spalte berechnen, und dann sukzessiv mit den anderen Spalten vorgehen, bis zur Ende der Matrix (d.h. unseres gesuchtes AN,K ). Die Laufzeit ist offensichtlich Θ (N · K). Algorithmus R EKURSIONSGLEICHUNG (K, N ) 1 2 3 4 5 6 7 8 9 10 11 A := leere (N + 1) × (K + 1) Matrix; for k = 0 to K do A0,k := 1; for n = 0 to N do An,0 := 1; for k = 1 to K do for n = 1 to N do An,k := An−1,k−1 + An−1,k ; end for end for return AN,K ; k=0 k=1 n=0 1 1 n=1 1 k=K 1 1 1 1 1 1 ... 1 1 1 n=N AN,K 1 3 Aufgabe 6 Diese Aufgabe ist ähnlich zur schon bekannten Aufgabe “Existiert eine Topologische Ordnung in diesem Graph?” (siehe Übungsserien), also wir können eine ähnliche Methode benutzen: Mit Hilfe einer modifizierten Tiefensuche (DFS) führen wir folgende Definition ein: Jeder Knoten besitzt einen “Status”, durch eine Farbe identifiziert: • Schwarze Knoten: wurden schon bearbeitet und haben keinen Einfluss mehr; • Graue Knoten: sind auf dem Stack (der Tiefensuche), also schon besucht; • Weisse Knoten: wurden noch nicht betrachtet. Unserem Algorithmus I S ACYCLIC (G) liegt die folgende einfache Beobachtung zugrunde: Immer, wenn wir einen Knoten ohne ausgehende Kanten in einem Graphen finden, können wir er als Schwarz markieren, da er sicher in keinen Zykel enthalten sein kann (ein solcher Knoten wird auch “Senke” genannt). Wir können somit durch Tiefensuche “am tiefsten” im Graph gehen, diese gefundene Senke (falls existiert) mit Schwarz markieren und dann zurück zum pred[] kommen: falls es keinen anderen weissen oder grauen ausgehenden Knoten gibt, dann markieren wir diesen grauen Knoten auf Schwarz und gehen wieder einen Schritt zurück, sonst gehen wir weiter mit einem beliebigen weissen ausgehenden Knoten. Falls wir einen grauen ausgehenden Knoten treffen (d.h. schon besucht, aber noch nicht eliminiert), dann haben wir einen Kreis gefunden! (sonst gehen wir vor, bis der ganze Graph schwarz ist). Einige Bemerkungen zum folgenden Pseudocode: • Mit Γ(v) sind nur die durch von v ausgehende Kanten erreichbaren Knoten gemeint. • Die äussere repeat-Schleife garantiert, dass die Tiefensuche den ganzen Graph bearbeitet und der Algorithmus nicht terminiert, bevor alle Knoten besucht wurden (auch falls es mehrere Komponenten gibt). Algorithmus I S ACYCLIC (G) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Total := |V |; S := new STACK; ∀v ∈ V : color[v] := white; repeat Wähle beliebigen Knoten v ∈ V mit color[v] = white; repeat if ∃u ∈ Γ(v) mit color[u] = grey then return “A directed Circle exists!”; if ∃u ∈ Γ(v) mit color[u] = white then color[v] := grey; S.Push(v); v := u; end if; if ∀u ∈ Γ(v) : color[u] = black then color[v] := black; Total := Total−1; v := S.Pop(); end if until v = nil; until Total = 0; return “A directed Circle doesn’t exist!”; Zur Korrektheit: Es ist klar, dass wir früher oder später entweder auf eine Senke oder einen bereits besuchten (also grauen) Knoten stossen: im zweiten Fall haben wir einen Zykel gefunden; wenn der zweite Fall nie eintritt, so ist der Graph ohne gerichtete Kreise (man nennt es “azyklisch”). Zur Laufzeit: Die Laufzeit von I S ACYCLIC ergibt sich aus derjenigen der Tiefensuche, ist also O (|V | + |E|). 4