Einführung in die Komplexitätstheorie

Werbung
Einführung in die Komplexitätstheorie
Inhaltsverzeichnis
1. Einleitung
2
2. Berechnungsmodelle
3
3. Die Komplexitätsklassen P/NP
6
4. Entscheidungsprobleme, Optimierungsprobleme, Aufzählungsprobleme
10
5. NP-vollständige Probleme
11
6. Schlusswort
18
7. Quellenverzeichnis
19
Dieser Lehrtext befasst sich mit einem wichtigen Thema in
der theoretischen Informatik, der Komplexitätstheorie. Der
Text eignet sich als kurzer Einblick oder als Grundlage,
wenn man sich damit tiefer beschäftigen will.
Geschrieben wurde er als Ergänzung zur Unterrichtseinheit
"Schwierige Probleme in der Informatik", die NP-Probleme
durch Entdeckendes Lernen lehrt. Die Dokumente sind im
Internet unter www.swisseduc.ch/informatik/
verfügbar.1. Einleitung
Viele Probleme, denen man im Alltag begegnet, sind auch ein Thema der
theoretischen Informatik. Ein Beispiel: Ein Sightseeing Bus möchte die Route
einer Tour festlegen. Sie soll beim Bahnhof starten und enden und 10
Sehenswürdigkeiten einschliessen. Bei jeder Attraktion soll die Tour genau
einmal vorbeikommen. Der Inhaber der Firma stellt sich folgende Fragen:
Gibt es überhaupt solch eine Tour? Wieviele Touren mit diesen Eigenschaften
existieren? Wie sehen die Routen aus?
Dieses Problem ist in der theoretischen Informatik als Hamilton Cycle
Problem bekannt. Meistens geht es aber in der theoretischen Informatik nicht
darum, die Lösung eines bestimmten Problems zu berechnen. Sondern
vielmehr analysiert man, unter welchen Bedingungen ein Problem überhaupt
lösbar ist. Für lösbare Probleme entwickelt man Algorithmen und stellt sich
die Frage nach der minimalen Anzahl Ausführungsschritten (Laufzeit).
Wenn man die Laufzeiten verschiedener Probleme kennt, kann man diese in
Gruppen einteilen. Solche Kategorien heissen in der theoretischen Informatik
Komplexitätsklassen. Wir betrachten nachfolgend die zwei wichtigsten
Klassen P und NP. Im abschliessenden Kapitel und als Krönung dieses
Lehrtextes, werden einige Probleme beschrieben, die in der Klasse NP liegen.
Wofür die Begriffe P und NP stehen und was sie bedeuten, wird später
erklärt.
Zuerst
einmal
lernen
wir
aber
die
Grundlagen
der
Komplexitätstheorie kennen.
2
2. Berechnungsmodelle
Unter einem Berechnungsmodell kann man sich ein theoretisches Modell
eines Computers vorstellen. Meistens geht man davon aus, dass es keine
physikalischen Grenzen gibt. Das bedeutet unter anderem, dass unendlich
viel Zeit und Speicherplatz vorhanden ist.
Die theoretischen Informatiker haben viele verschiedene Modelle eingeführt.
Ein einfaches Modell sind die Markov Algorithmen. Das berühmteste und
wahrscheinlich auch bedeutendste ist die Turingmaschine.
Beide
Berechnungsmodelle sind universell. Das heisst sie sind in der Lage, alle
lösbaren Probleme zu lösen. Mit einem universellen Berechnungsmodell kann
man jedes andere universelle Berechnungsmodell simulieren. Dies ist ein
berühmte These und wurde von Church und Turing eingeführt.
Da die Turingmaschine benutzt wird, um die Klassenkomplexität
bestimmen, werden wir uns auf dieses Modell konzentrieren.
zu
Turingmaschinen
Der Mathematiker Alan Turing hat sich überlegt, wie ein Mensch vorgeht,
wenn er eine mathematische Aufgabe löst. Normalerweise schreibt er dazu
Symbole auf ein Blatt Papier, zum Beispiel ein Häuschenpapier. Mit der Hand
bewegt er den Bleistift nach links und rechts. Das Gehirn steuert. Aus dieser
Überlegung hat Turing die Turingmaschine entworfen.
Eine Turingmaschine besteht aus drei Elementen. Zum einen aus einem
Speicherband mit unendlich vielen Häuschen. In jedem dieser Häuschen
kann ein Zeichen gespeichert werden. Dies entspricht dem Häuschenpapier.
Auf dem Speicherband sitzt ein Schreib- und Lesekopf. Er kann sich
schrittweise nach links oder rechts bewegen oder stehenbleiben. Im selben
Schritt kann er ein Zeichen schreiben oder löschen. Dies entspricht dem
Bleistift, den der Mensch mit der Hand führt. Als drittes Element enthält eine
Turingmaschine ein Programm mit endlichen vielen Zuständen. Als Analogon
beim Menschen taugt das Gehirn. Durch die verschiedenen Zustände im
Programm wird das Verhalten der Turingmaschine gesteuert.
3
Nun kennen wir die Konfiguration einer solchen Maschine, aber wie
funktioniert sie? Die Details sind hier nicht so wichtig, da wir die
Turingmaschinen nur als Mittel zur Laufzeitanalyse kennenlernen. Aber hier
trotzdem einen kleinen Einblick: Auf dem Band stehen zu Beginn gewisse
Zeichen. Das Programm startet mit dem ersten Zustand. Der Zustand
definiert, was der Schreib/-Lesekopf macht. Je nachdem, welches Zeichen
der Lesekopf auf dem Band liest, springt man im Programm zu dem
entsprechenden Zustand. Werden spezielle akzeptierende Zustände erreicht,
stoppt die Turingmaschine. Dann enstprechen die Zeichen auf dem Band
oder der erreichte Zustand der Ausgabe des Programms.
Man unterscheidet zwischen deterministischen und nichtdeterministischen
Turingmaschinen. Beide können dasselbe berechnen. Deterministische
Turingmaschinen haben bei gleicher Eingabe immer nur eine Möglichkeit für
einen Zustandsübergang im Programm. Das heisst, das Programm läuft bei
gleicher Eingabe stets gleich ab. Nichtdeterministische Turingmaschinen
haben mehrere Möglichkeiten für den Zustandsübergang. Die Maschine wählt
einen der Übergänge. Man nimmt an, dass die Maschine gut raten kann und
so meistens der richtige nächste Zustand erreicht wird. Dieses Konzept mag
auf den ersten Blick nicht einleuchten. Wichtig ist nur, dass man im Kopf
behält, dass es zwei Arten von Turingmaschinen gibt.
Das faszinierende an einer Turingmaschine ist, dass sie mit den drei
Operationen lesen, schreiben und Kopf bewegen jedes lösbare Problem lösen
kann. Sämtliche mathematischen Grundoperationen wie Addition und
Multiplikation lassen sich damit simulieren. Durch Kombination der
Grundoperationen kann man alle mathematischen Funktionen erzeugen.
Als Beispiel betrachten wir eine Turingmaschine, die für eine beliebige
Zeichenkette feststellt, ob sie aus n Nullen gefolgt von n Einsen besteht. Die
Zeichenkette auf dem Speicherband sei auf beiden Seiten durch ein
Doppelkreuz begrenzt. Der Lesekopf steht zu Beginn auf dem Doppelkreuz
links. Falls die Eingabe korrekt ist, soll die Turingmaschine mit einem leeren
Speicherband terminieren, ansonsten soll sie mit einem nicht-leeren Band
stoppen. Ein Beispiel einer (ungültigen) Zeichenkette: #000011101#
Wie können wir dieses Problem nun mit einer Turingmaschine lösen? Da die
Turingmaschine keinen internen Speicher hat, um die Zeichen zu zählen, ist
es am Einfachsten, die Nullen und Einsen jeweils paarweise zu löschen. Dies
erreichen wir mit vier Zuständen.
4
1. Gehe ganz nach links
2. Lese und lösche Zeichen (stoppe falls keine Null)
3. Gehe ganz nach rechts
4. Lese und lösche Zeichen (stoppe falls keine Eins)
Diese vier Schritte werden so lange ausgeführt, bis ein Fehler gefunden wird
oder bis alle Zeichen gelöscht worden sind. Wird im vierten Schritt keine Eins
gelesen, schreibt die Maschine ein Doppelkreuz. Ansonsten würde sie bei
Zeichenketten, die genau eine Null zuviel haben, auf dem leeren Band
terminieren.
Dieses Beispiel wurde der Software TuringKara entnommen. Das Programm
bietet einen spielerischen Einstieg in Turingmaschinen. Die Software ist unter
www.swisseduc.ch/informatik/karatojava/turingkara/ erhätlich.
5
3. Die Komplexitätsklassen P/NP
Unter Komplexität versteht man in der Informatik die Anzahl Rechenschritte,
die ein Algorithmus für ein Problem im ungünstigsten Fall benötigt, um es zu
lösen. Oft spricht man auch von der worst-case Laufzeit.
Interessant wäre doch, wenn man die Probleme nach Laufzeit ordnen kann.
Dann sind Überlegungen möglich wie "wenn ich Problem A in kurzer Zeit
lösen kann und Problem B in derselben Klasse ist, dann kann ich Problem B
auch in kurzer Zeit lösen". Zu diesem Zweck haben die theoretischen
Informatiker Komplexitätsklassen definiert.
Eine Komplexitätsklasse ist eine untere Laufzeit-Schranke für jeden
Algorithmus, der darin vorkommt. Um die Klassenkomplexität zu bestimmen,
wird die Turingmaschine hinzugezogen. Man zählt dazu die Anzahl der
durchlaufenen Zustandsübergänge im Programm, bis die Turingmaschine für
das jeweilige Problem hält. Die Schwierigkeit besteht darin, die Probleme in
die Klassen einzuteilen.
Ist die Einteilung aber erst einmal vorgenommen, ist das extrem praktisch.
Denn Probleme, die in derselben Klasse liegen, können mit einem optimalen
Algorithmus mit ungefähr demselben Rechenaufwand gelöst werden.
Die Einteilung erfolgt entweder nach Zeitaufwand oder Speicherverbrauch.
Wir ignorieren im folgenden den Speicherverbrauch und konzentrieren uns
auf
die
Zeitkomplexität.
Es
existieren
viele
verschiedene
Zeitkomplexitätsklassen. Wir beschränken uns auf die zwei wichtigsten, die
Klassen P und NP.
Die Klasse P
In der P-Klasse befinden sich sequentielle Algorithmen, deren Anzahl
Berechnungsschritte
durch
ein
Polynom
beschränkt
wird.
Ein
Berechnungsschritt ist ein Zustandsübergang der deterministischen
Turingmaschine, die den Algorithmus ausführt.
Wir betrachten als Beispiel den Suchalgorithmus SelectionSort. Als Input
haben wir n Zahlen in unsortierter Reihenfolge. SelectionSort wählt im
unsortierten Bereich das Minimum und vertauscht es mit dem ersten Element
dieses Teilbereichs. Dann wird SelectionSort auf den neuen unsortierten
Teilbereich angewendet. Wir analysieren die Komplexität: Um anfangs das
kleinste Element zu finden, sind n-1 Vergleiche notwendig. Im zweiten
Schritt benötigt der Algorithmus n-2 Vergleiche. Insgesamt macht der
Algorithmus (n-1)+(n-2)+...+2+1 = n(n-1)/2 = n^2/2 – n/2 Vergleiche plus
eine konstante Anzahl Vertauschungen. Die Anzahl Rechenschritte sind also
durch ein quadratisches Polynom begrenzt. Daher liegt SelectionSort in der
6
Komplexitätsklasse P.
Fast alle Algorithmen, die in Einführungsvorlesungen der Informatik
kennengelernt werden, liegen in dieser Klasse. So zum Beispiel Such- und
Sortieralgorithmen (zum Beispiel binäre Suche und Quicksort).
Die meisten Probleme in dieser Klasse sind einfach zu lösen. Einfach
bedeutet ohne grossen Rechenaufwand. Natürlich ist das in der Praxis nur
bedingt anwendbar für Probleme, die durch Polynome hohen Grades
begrenzt sind.
Die Klasse NP
NP steht für nichtdeterministisches Polynom. In der Komplexitätsklasse NP
liegen Probleme, die von einer nichtdeterministischen Turingmaschine in
polynomialer Zeit entschieden werden können. Es existiert eine zweite
Definition: In NP liegen alle Probleme, deren Lösung von einer
deterministischen Turingmaschine überprüft werden kann.
Zum besseren Verständnis werde ich dies umformulieren. Probleme, deren
Lösung von einer nichtdeterministischen Turingmaschine in polynomialer Zeit
berechnet werden können, liegen in der Klasse NP. Die zweite Definition ist
etwas einfacher zu verstehen und benötigt keine nichtdeterminischte
Turingmaschine. Falls wir eine mögliche Lösung eines Problems bereits
kennen und sich eine solche Lösung von einer deterministischen
Turingmaschine überprüfen lässt, dann liegt dieses Problem in NP.
Für die Praxis hat dies eine grosse Bedeutung. Alle Probleme in NP lassen
sich (wahrscheinlich) nicht effizient lösen. Je nach Datenmenge ist die
Rechenzeit so gross, dass sie selbst mit den modernsten Computern nicht
lösbar sind.
Ein klassisches Beispiel für NP-Probleme sind Probleme, bei denen alle
Möglichkeiten durchprobiert werden müssen, um eine Lösung zu finden. Ein
konkretes Beispiel: Gegeben eine Menge von Ganzzahlen. Entscheide, ob
eine Teilmenge dieser Menge aufaddiert exakt Null ergibt. Dieses Problem
lässt sich lösen, indem man alle Teilmengen durchprobiert, bis man eine
Lösung findet. Im schlechtesten Fall müssen 2^n Teilmengen getestet
werden. Die Lösung lässt sich von einer deterministischen Turingmaschine
überprüfen.
7
Problemreduktionen
Im 3-SAT Problem geht es um die Erfüllbarkeit logischer Formeln in
konjunktiver Normalform mit höchstens 3 Literalen pro Klausel. Wir kennen
verschiedene Algorithmen und deren Laufzeit für das Problem. Es wurde
bewiesen, dass das 3-SAT Problem in NP liegt. Nun wäre es doch praktisch,
wenn wir neue Probleme unbekannter Komplexität mit 3-SAT vergleichen
und damit neue Erkenntnisse gewinnen könnten. Diese Technik wird
Problemreduktion genannt.
Mit Problemreduktionen kann man die Komplexität zweier Probleme
miteinander vergleichen. Angenommen ein Problem A kann zu einem
Problem B reduziert werden. Problem B liegt in NP. Die Reduktion gibt uns
dann Informationen über die Komplexität des unbekannten Problems.
Aber welche Informationen und was genau bedeutet “reduzieren”? Also:
Gegeben ein Problem A unbekannter Komplexität und ein Problem mit
Lösungsalgorithmus B bekannter Komplexität. Mit einer Codierungsfunktion
überführen wir den Input des Problems A in den Input des Problems B. Wir
wenden den Algorithmus B auf diesen Input an. Eine Decodierungsfunktion
wandelt den erhaltenen Output wieder zurück. Wir haben damit Problem A
auf Problem B reduziert. Ist dies durchführbar und sind die
Codierungsfunktionen polynomial, dann haben wir Problem A zu Problem B
reduziert. Wir schliessen daraus, dass Problem A höchstens so schwierig ist
wie Problem B. Wir können auch zeigen, dass Problem A mindestens so
schwierig ist wie Problem B, indem wir Problem B auf Problem A reduzieren.
Oft reduziert man Probleme zu 3-SAT. Das Graphenfärbbarkeitsproblem lässt
sich zum Beispiel auf 3-SAT reduzieren. Wir betrachten jedoch ein
einfacheres Beispiel. Wir wissen, dass “Element Uniqueness” (gegeben n
Elemente, entscheide ob alle Elemente verschieden sind) mindestens nlogn
benötigt. Daraus beweisen wir mittels Reduktion eine untere Schranke für
Sortieren:
Die Codierungsfunktion c macht nichts beziehungsweise verändert den Input
nicht. Die Decodierungsfunktion d geht die sortierte Liste durch. Falls zwei
benachbarte Werte gleich sind, ist die Antwort nein, ansonsten ja. Dies kann
in linearer Zeit berechnet werden. Somit haben wir Element Uniqueness auf
Sortieren reduziert und bewiesen, dass Sortieren ebenfalls mindestens nlogn
benötigt.
8
NP-Vollständigkeit
Die NP-vollständigen Probleme sind eine Untermenge der Probleme in NP. Ein
Problem ist genau dann NP-vollständig wenn es in NP liegt und sich jedes
Problem in NP auf dieses Problem polynomial reduzieren lässt. Meistens zeigt
man die NP-Vollständigkeit eines Problems A, indem man ein NPvollständiges Problem auf A polynomial reduziert.
NP-vollständige Probleme sind besonders schwierig zu lösen. Man nimmt an,
dass es keine effizienten Algorithmen für solche Probleme gibt. Momentan
benötigen die besten bekannten Algorithmen exponentielle Zeit in der
Problemgrösse. Daher sind optimale Algorithmen nur für kleine
Probleminstanzen in vernünftiger Zeit durchführbar. Oft greift man daher auf
Approximationen und Heuristiken zurück. Approximationen liefern nicht
immer die optimale Lösung, jedoch eine Lösung, die oft nur wenig von der
optimalen Lösung entfernt ist. Gute Heuristiken liefern oftmals eine gute oder
sogar die korrekte Lösung, können aber auch in Zustände geraten, in denen
sie nie terminieren. NP-vollständige Probleme und konkrete Heuristiken
werden im letzten Kapitel besprochen.
Falls für ein NP-vollständiges Problem ein effizienter Algorithmus gefunden
würde, dann wäre jedes NP-vollständige Problem effizient lösbar. Man nimmt
an, dass keine effizienten Algorithmen existieren, konnte das aber noch nie
beweisen. Dies führt uns zur nächsten Frage.
Ist P = NP?
Diese Frage beschäftigt zur Zeit viele Informatiker und ist eine der grossen
ungelösten Fragen in der Informatik. Preise in Millionenhöhe wurden für die
Lösung ausgesetzt.
Wieso ist aber diese Frage so wichtig? Würde bewiesen werden, dass P = NP,
also die beiden Komplexitätsklassen äquivalent sind, dann würde dies
bedeuten, dass auch Probleme in NP effizient gelöst werden könnten.
Dies hätte nicht nur positive Auswirkungen. Die Kryptographie nützt die
Schwierigkeit
von
NP-vollständigen
Problemen
aus,
um
sichere
Verschlüsselungssysteme zu entwerfen. Wären nun NP-Probleme effizient
lösbar, würden alle solchen Verschlüsselungssysteme keine Sicherheit mehr
bieten.
Man nimmt an, dass P ungleich NP ist. Solange dies nicht bewiesen wird,
kann es aber doch möglich sein, dass die Komplexitätsklassen äquivalent
sind. Deshalb wird in vielen Beweisen als Bemerkung “falls PNP” vermerkt.
9
4. Entscheidungsprobleme, Optimierungsprobleme,
Aufzählungsprobleme
Wir haben in der Einleitung bereits das Hamilton Cycle Problem
kennengelernt. Eine formalere Definition könnte so lauten: ein Hamilton
Kreis in einem Graphen G=(V,E) ist ein Zyklus (Kreis), der alle Knoten in V
genau einmal besucht. V entspricht der Knotenmenge, mit E bezeichnet man
die Menge aller Kanten.
Die Definition für das Cliqueproblem: eine Clique in einem Graphen G=(V,E)
ist eine Untermenge V', so dass für alle Knoten u,v in V' gilt: (u,v) ist eine
Kante in E. Vereinfacht gesagt ist eine Clique eine Untermenge an Knoten, so
dass alle Knoten dieser Untermenge benachbart sind. Benachbart bedeutet
durch eine Kante verbunden.
Alle diese Probleme lassen sich weiter unterteilen. Als Optimierungsproblem,
Entscheidungsproblem oder als Aufzählungsproblem.

Entscheidungsprobleme
Hat der Graph G einen Hamilton Kreis? Hat der Graph G eine Clique mit 5
Knoten?
Die Antwort von Entscheidungsproblemen zu finden ist meistens
schwierig. Einfacher ist es, eine positive Antwort auf ihre Richtigkeit zu
prüfen.

Optimierungsprobleme
Finde die grösste Clique in einem Graphen.
Die Antwort zu finden und sie zu überprüfen ist normalerweise schwierig.
Wie finde ich heraus, dass eine Clique tatsächlich die Grösste ist?
Trotzdem ist das überprüfen meistens einfacher als die Antwort zu finden.

Aufzählungsprobleme
Wieviele Cliquen oder Hamilton Kreise existieren in einem Graphen?
Aufzählungsprobleme benötigen viel Zeit, sind aber meist einfach zu
lösen. Man überprüft durch Backtracking alle möglichen Fälle und findet so
die Lösung.
Die Komplexitätstheorie befasst sich häufig mit Entscheidungsproblemen. In
der Praxis sind oft Optimierungsprobleme von Interesse. Führe dir nochmals
das Beispiel aus der Einleitung vor Augen. Der Reiseveranstalter sucht
Routen
für
die
Sightseeing-Tour.
Dies
entspricht
einem
Entscheidungsproblem. Falls er in einem zweiten Schritt die kürzeste Tour
sucht, muss er das Optimierungsproblem lösen.
10
5. NP-vollständige Probleme
Hamilton Kreis
Ein Hamilton Kreis ist ein Pfad, der jeden Knoten genau einmal besucht.
Existiert in einem Graphen ein Hamilton Kreis? Das Problem rund um diese
Frage ist ein schwieriges Problem und NP-vollständig.
Eine Stadt kann einfach als Graph betrachtet werden, indem man sich die
Kreuzungen als Knoten und die Strassenabschnitte als Kanten vorstellt. Als
Beispiel für das Hamilton Kreis Problem in solch einem Graphen haben wir
bereits in der Einführung die Suche nach einer Tour des Reisebusses
kennengelernt.
Ein Hamilton Kreis lässt sich unter anderem mit Backtracking finden. Man
beginnt bei einem Knoten und speichert die Pfade ausgehend von diesem
Knoten zu unbesuchten Knoten. Für jeden Pfad speichert man neue Pfade
ausgehend vom letzten Knoten zu unbesuchten Nachbarn. Diese Schritte
führt man durch, bis ein Hamilton Kreis gefunden wird oder bis alle Pfade
besucht wurden.
Wir können das Problem sowohl für ungerichtete als auch für gerichtete
Graphen lösen, d.h. wenn die Kanten eine Richtung haben. Eine gerichtete
Kante kann man mit einer Einbahnstrasse vergleichen. Ungerichtete Graphen
lassen sich auf gerichtete reduzieren.
Eine wichtige Anwendung von Hamilton Kreisen treffen wir im nächsten
Problem an.
Travelling Salesman (Problem des Handelsreisenden)
Das Travelling Salesman Problem ist verwandt mit dem Hamilton Kreis
Problem. Den Kanten sind nun aber Gewichte zugewiesen. In der
Entscheidungsvariante beantwortet man die Frage, ob in einem Graphen eine
Tour existiert, die kürzer als k ist. Im Optimierungsproblem wird die kürzeste
Travelling Salesman Tour gesucht. Eine Tour besucht jede Stadt genau
einmal.
Wahrscheinlich kennen viele Leute dieses Problem aus dem Alltag. Es
modelliert das Problem, mehrere Orte nacheinander auf dem kürzesten Weg
zu besuchen und zum Anfangsort zurückzukehren. Handelsreisende, die
11
verschiedene Orte besuchen und den kürzesten Weg gehen möchten,
müssen dieses Problem lösen können, daher der Name. Auch beim
Postbeamten, der die Zeitungen austrägt, tritt dieses Problem auf. Jedoch ist
dies nicht das beste Beispiel. Wieso sollten Handelsreisende eine Stadt oder
Postbeamte ein Haus nicht mehrmals besuchen, wenn sie dadurch Zeit
sparen?
Wir betrachten nun Algorithmen für das euklidische Travelling Salesman
Problem. Im euklidischen TSP Problem entspricht das Gewicht einer Kante
seiner Länge.
Mit Backtracking lässt sich dieses Problem natürlich lösen, jedoch sehr
ineffzient. Der Algorithmus wählt die erste Kante und kreiert neue Pfade,
indem er Kanten zu den unbesuchten Kanten hinzufügt. Dies macht er
solange, bis entweder alle Pfade eine Tour sind oder bis alle Pfade länger als
die bereits gefundene kürzeste Tour ist.
Dieses Problem fehlt in keinem Informatikunterricht und ist gut untersucht.
Es existieren auch zahlreiche Heuristiken. Die Nearest Neighbour Heuristik
beginnt beim ersten Knoten und wählt immer den nächsten (dessen
Verbindungskante das kleinste Gewicht hat) unbesuchten Knoten bis kein
Knoten mehr übrig bleibt. Das geht natürlich sehr schnell, ist aber
dementsprechenend ungenau. Etwas besser schneidet die konvexe Hülle
Heuristik ab. Sie erzeugt zuerst die konvexe Hülle aller Knoten. Dann wird
der Knoten ausgewählt, welcher der Tour am nächsten liegt und hinzugefügt.
Der Algorithmus terminiert, wenn alle Knoten Teil der Tour sind.





Die Greedy Heuristik wählt die Kante mit dem kleinsten Gewicht und fügt sie
zur Tour hinzu, sofern die Kante keinen Zyklus erzeugt, bis kein Knoten mehr
übrig bleibt. Two-Optimization generiert zuerst eine zufällige Tour. Danach
sucht sie zwei Kanten und tauscht deren Endknoten, falls dies die Tour
verkleinert. Dies macht der Algorithmus, bis keine zwei solchen Kanten mehr
gefunden werden.
Nochmals zur Erinnerung: das Problem des Handlungsreisenden ist NPvollständig. Das bedeutet, es ist zwar lösbar, jedoch mit erheblichem
Aufwand. Alle bekannten korrekten Algorithmen sind so langsam, dass sie
schon bei Graphen mit 300 Knoten nicht mehr in nützlicher Zeit ein Resultat
generieren. Ein Algorithmus, der alle Pfade durchsucht, müsste in einem
12
Graphen mit 300 Knoten ungefähr 300! (mein Taschenrechner kann nicht
einmal mehr 300! berechnen) Touren durchlaufen. Deshalb braucht man die
Heuristiken, die als Abschätzung oftmals genügen.
Das Sightseeing Bus Unternehmen könnte damit die kürzeste Tour in der
Stadt berechnen, um Benzin und Zeit zu sparen.
Färbung von Graphen (Colorability)
Eine beliebte Aufgabe im Geographieunterricht ist es, eine Landkarte mit
verschiedenen Farbstiften so einzufärben, dass keine benachbarten Länder
dieselbe Farbe aufweisen. Du fragst dich eventuell, wieviele verschiedene
Buntstifte du dazu benötigst. Reichen 4 Farbstifte aus? Doch so einfach ist
dieses Problem nicht zu lösen. Es handelt sich hierbei um einen Spezialfall
des Graphfärbungsproblem.
Jedem Knoten wird eine Farbe zugewiesen. Eine Färbung ist gültig, wenn
keine benachbarten Knoten mit derselben Farbe eingefärbt wurden. Knoten
werden benachbart genannt, wenn sie durch eine Kante direkt verbunden
sind.
gültige Färbung
ungültige Färbung
Ein Graph heisst k-färbbar, wenn er mit k Farben eingefärbt werden kann.
Das kleinstmögliche k zu finden, ist ein NP-vollständiges Problem und daher
aufwändig zu lösen.
Auch dieses Problem lässt sich mit Backtracking lösen. Backtracking testet
für ein gegebenes k alle möglichen Färbungen bis entweder eine Lösung
gefunden wird oder alle Möglichkeiten erschöpft sind. Das minimale k lässt
sich so finden: Man lässt den Algorithmus für k=1,2,... laufen, bis eine
Färbung gefunden wird.
Die Anzahl Ausführungsschritte ist bei einer Heuristik viel geringer. Jedoch
kann nicht garantiert werden, dass das Resultat korrekt ist. Die Greedy
Heuristik sucht den Knoten mit den meisten nicht zugewiesenen Kanten. Eine
Kante ist nicht zugewiesen, falls einer seiner Knoten nicht eingefärbt ist.
Nach dem Färben dieses Knotens fährt er bei seinen Nachbarn
gleichermassen weiter. Der Algorithmus terminiert, wenn er eine gültige
Färbung gefunden hat oder falls ein Knoten nicht eingefärbt werden kann.
13
Um auf das Landkartenbeispiel zurückzukommen: Du kannst Dir die
Landkarte als Graphen vorstellen. Länder werden zu Knoten. Die Knoten
benachbarter Länder werden durch eine Kante verbunden.
Die gute Nachricht: Eine Landkarte ergibt einen planaren Graphen, das heisst
die Kanten schneiden sich nur in den Knoten. Falls jedes Land aus nur einer
zusammenhängenden Fläche besteht, benötigt die Färbung höchstens aus 4
Farben. Die schlechte Nachricht: Trotz dieser Einschränkung ist das Problem
immer noch NP-vollständig .
Im Alltag existieren weitere prominente Beispiele der Graphenfärbbarkeit,
denen wir täglich begegnen: Bei einer Ampelschaltung dürfen gewisse
Ampeln nicht gleichzeitig auf grün geschaltet werden. Bei der
Stundenplanerstellung sind die Stunden, die nicht gleichzeitig stattfinden
dürfen (gleiche Lehrer, Klasse, Zimmer) miteinander in Konflikt. Beide
Probleme lassen sich auf das Graphenfärbbarkeitsproblem abbilden.
Vertex Cover (Knotenüberdeckung)
Ein Vertex Cover ist eine Menge an Knoten, die alle Kanten abdecken. Eine
Kante ist abgedeckt, wenn mindestens einer seiner Knoten im Vertex Cover
liegt. Die Grösse eines Vertex Cover ist die Anzahl seiner Knoten.
Vertex Cover der Grösse 4
Auch dieses Graphenproblem lässt sich als ein Entscheidungs- und
Optimierungsproblem formulieren. In der ersten Variante fragt man sich, ob
ein gegebener Graph ein Vertex Cover der Grösse k besitzt. Im
Optimierungsfall sucht man das minimale Vertex Cover, also die minimale
Anzahl Knoten, so dass alle Kanten abgedeckt sind. Wie alle Probleme in
diesem Kapitel ist auch dieses NP-vollständig.
Wir betrachten einen Algorithmus für das Entscheidungsproblem. Gegeben ist
ein Graph und man soll prüfen, ob alle Kanten mit 5 Knoten abgedeckt
werden können. Backtracking findet in jedem Fall die richtige Lösung. Der
Algorithmus erstellt eine Liste mit allen Knotenmengen der Grösse 5. Dann
prüft er diese Knotenmengen darauf, ob sie ein gültiges Vertex Cover sind.
Er terminiert, falls er eine Lösung gefunden hat oder alle Möglichkeiten
getestet hat.
14
Für die Optimierungsvariante existiert eine Approximation, die ein Vertex
Cover findet, das höchstens doppelt so gross wie das minimale ist. Der
Algorithmus wählt zufällig eine Kante und fügt deren Knoten zum Vertex
Cover hinzu. Dann werden die beiden Knoten und die angrenzenden Kanten
gelöscht. Der Algorithmus beginnt von vorne bis die Knotenmenge ein
gültiges Vertex Cover darstellt.
Ein vielleicht etwas gesuchtes Anwendungsbeispiel von Vertex Cover ist die
Positionierung von Überwachungskameras in einem Gebäude.
Man will
überall dort Kameras installieren, wo mehrere Gänge aufeinandertreffen. Aus
Kostengründen ist man natürlich daran interessiert, mit möglichst wenigen
Kameras auszukommen.
Clique
Unter einer Clique versteht ein Nichtinformatiker eine Gruppe Menschen, die
miteinander befreundet sind. Also kennt in einer Clique jeder jeden.
Diese Erkenntnis projizieren wir nun auf einen Graphen. Die Knoten
entsprechen den Menschen. Eine Kante zwischen zwei Menschen bedeutet,
dass sie sich kennen. Eine Clique in einem Graphen ist eine Knotenmenge, in
der jeder Knoten zu jedem anderen Knoten benachbart ist. Es ist also ein
vollständiger Subgraph des ganzen Graphen. Wir können auch sagen: in
einer Clique kennt jeder Knoten jeden. Das Problem, die maximale Clique in
einem Graphen zu finden, ist NP vollständig. Es existiert also wahrscheinlich
kein effizienter Algorithmus, der die maximale Clique berechnet.
Der Backtracking Algorithmus arbeitet ähnlich wie beim Vertex Cover
Problem. Soll eine Clique der Grösse 3 gefunden werden, prüft er alle
Knotenmengen der Grösse 3. Dies solange bis er eine Lösung findet oder alle
Möglichkeiten erschöpft sind.
Man könnte den Algorithmus folgendermassen verbessern: sucht man nach
einer Clique der Grösse k, können alle Knoten gelöscht werden, die weniger
als k-1 Nachbarn besitzen. Denn solche Knoten können niemals zu einer
Clique der Grösse k gehören. Ebenfalls können dann deren Kanten gelöscht
werden und eventuell weitere Knoten ignoriert werden.
15
Independent Set (Unabhängige Menge)
In einer unabhängigen Menge sind keine zwei Knoten benachbart. In solch
einer Menge gilt also für je zwei Knoten, dass sie nicht durch eine Kante
verbunden sind.
Dieses Problem ähnelt dem vorangehenden Cliquenproblem. Eine Clique in
einem
Graphen
entspricht
einer
unabhängigen
Menge
in
dem
Komplementgraphen. Den Komplementgraphen erhält man, wenn man alle
Kanten des ursprünglichen Graphen löscht und die zuvor unverbundenen
Knoten miteinander verbindet. Dies führt uns gleich zu einer Lösung. Wir
können ein maximales Independent Set finden, indem wir die Clique im
Komplementgraphen berechnen. Daraus lässt sich auch schliessen, dass das
Independent Set ebenfalls NP vollständig sein muss.
Natürlich können wir die Lösung auch direkt finden. Soll eine unabhängige
Menge der Grösse k berechnet werden, sucht Backtracking alle Untermengen
der Grösse k nach einer unabhängigen Menge ab.
Es gibt Prominente, die mögen sich nicht besonders. Dies muss zum Beispiel
bei den Oscarverleihungen beachtet werden. Wie platziere ich die
Schauspieler, Regisseure und Produzenten im Saal so, dass keine zwei
zerstrittene Promis neben- oder hintereinander sitzen müssen? Der
Organisator kann die Stühle als Knoten darstellen und jene Stühle durch eine
Kante verbinden, die neben- oder hintereinander liegen. Mit einer
unabhängigen Menge findet er Stühle, die zu keinem anderen Stuhl aus der
unabhängigen Menge benachbart sind.
Satisfiability (Erfüllbarkeit logischer Formeln)
Gegeben ist eine logische Formel und gesucht ist eine Belegung der
Variablen, so dass die Formel erfüllt ist. Häufig wird 3-SAT, eine
Vereinfachung dieses Problems betrachtet.
In 3-SAT sind die Formeln in konjunktiver Normalform mit höchstens 3
Literalen pro Klausel gegeben. Ein Beispiel einer solchen Formel ist (x1  x2
 x3)  (x1  x2  x3)  (x2  x3). Eine Belegung, die diese Formel
erfüllt ist x1=0, x2=1, x3=1.
Cook hat bewiesen, dass das Erfüllbarkeitsproblem NP-vollständig ist. Diese
Eigenschaft erleichtert die NP-Vollständigkeitsbeweise anderer Probleme.
Durch die Reduktion auf Satisfiabilty in polynomialer Zeit kann man die NP16
Vollständigkeit eines Problems zeigen. Satisfiability ist also sozusagen die
Mutter aller NP-vollständigen Probleme. Falls für Satisfiability ein effizienter
Algorithmus gefunden würde, dann würden für alle NP-vollständigen
Probleme effiziente Algorithmen existieren.
Eine Belegung, welche die Formel erfüllt, kann man mittels Backtracking
finden. Man setzt alle Variablen auf false und probiert alle Möglichkeiten
durch, bis eine Belegung gefunden wird, welche die Formel erfüllt;
vorausgesetzt eine solche Belegung existiert.
Ein physikalisches Modell versucht die Formel mit physikalischen Kräften zu
lösen. Dabei versucht jede Klausel ihre Literale in die Richtung zu ziehen, in
der die Klausel erfüllt ist. Je näher die Literale am günstigen Wert liegen,
desto stärker ist die ziehende Kraft. Beim 3-SAT Beispiel von oben versucht
die zweite Klausel x2 nach 1 zu ziehen. X1 und x3 zieht er in Richtung 0.
17
6. Schlusswort
Wie man sieht, ist die Komplexitätstheorie ein faszinierendes Gebiet. Auf den
ersten Blick ist sie zwar sehr theoretisch, was abschrecken kann. Wenn man
sich aber näher damit befasst, sieht man, dass viele Probleme alles andere
als realitätsfremd sind.
Wenn man sich näher damit befassen möchte, eignet sich folgendes:
Als erstes die Software GraphBench, die sich mit NP-vollständigen Problemen
befasst. Das Programm führt spielerisch in ausgewählte Probleme ein. Man
kann damit alle in diesem Text erwähnten Probleme betrachten und deren
Algorithmen visualisieren.
Von derselben Gruppe sind auch Kara (Turingmaschinen) und Exorciser
(endliche Automaten) entwickelt worden, die ich auch empfehlen kann.
Das Buch “Das Affenpuzzle und weitere bad news aus der Computerwelt” von
David Harel behandelt ähnliche Themen wie dieser Lehrtext, jedoch
ausführlicher. Der Autor verzichtet auf unnötigen Formalismus, dadurch liest
sich das Buch sehr flüssig.
Weitere Informationen kann man den Quellenangaben
entnehmen.7. Quellenverzeichnis

Wikipedia (verschiedene Autoren): 2002-2004,
http://de.wikipedia.org/wiki/Kategorie:Theoretische_Informatik

Harel David:Das Affenpuzzle und weitere bad news aus der
Computerwelt, 2002 (Springer).

Nievergelt J.: Lecture Notes “Theory of computation”, 2002.

GraphBench
http://www.swisseduc.ch/informatik/graphbench/

TuringKara
http:// www.swisseduc.ch/informatik/karatojava/turingkara/
18
Herunterladen