Institut für Mathematische Optimierung Fortgeschrittenenpraktikum - WS2006/07 Vorbereitungsaufgabe: Einfache Heuristiken für das TSP Dennis Egbers 06.10.2006 Theoretischer Hintergrund Rundreiseprobleme sind jedem von uns bekannt, da sie in vielfältiger Weise im eigenen Leben auftauchen. In mathematischer Hinsicht modelliert man Rundreiseprobleme meist durch Graphen G = (V, E). Dabei ist jede Kante (i, j) ∈ E (i, j ∈ V ) mit einem Gewicht cij versehen, das z.B. die Länge der Strecke zwischen den beiden Orten symbolisiert, die durch die mit der Kante inzidierenden Knoten repräsentiert werden. Man kann grundsätzlich unterscheiden zwischen solchen Rundreiseproblemen, bei denen alle Kanten eines Graphen durchlaufen werden müssen, und solchen, bei denen alle Knoten durchlaufen werden müssen. Wir wollen uns im folgenden mit Rundreiseproblemen des zweiten Types beschäftigen. Ein einfaches und sicher bekanntes Problem dieser Art ist das Hamilton-KreisProblem, bei dem entschieden werden soll, ob ein Graph G hamiltonsch ist. Definition. Sei G = (V, E) ein (zusammenhängender) Graph. Ein HamiltonKreis ist ein geschlossener Zug von Kanten aus E, der alle Knoten aus V genau einmal enthält. Analog ist ein Hamilton-Pfad ein (gegebenenfalls nicht geschlossener) Zug von Kanten aus E, der alle Knoten aus V genau einmal berührt. Man nennt einen Graphen hamiltonsch, wenn er einen Hamilton-Kreis enthält, und semi-hamiltonsch, wenn er einen Hamilton-Pfad enthält, nicht aber einen Hamilton-Kreis. Man kann zeigen, dass das Hamilton-Kreis-Problem N P-vollständig ist - im Gegensatz zum Problem, ob es einen Kreis in einem Graphen gibt, der alle Kanten genau einmal berührt. Dieses Problem, das sogenannte Euler-Tour-Problem, ist effektiv lösbar. In praktischen Anwendungen ist man meist nicht nur daran interessiert, einen Hamiltonschen Kreis in einem Graphen zu finden, sondern auch daran, unter allen solchen Kreisen einen günstigsten zu ermitteln. Auf dieser Fragestellung basiert das Problem des Handelsreisenden, bei dem man versucht mit möglichst geringen Gesamtkosten alle Knoten eines Graphen genau einmal zu besuchen. Definition. Es sei ein vollständiger Graph Kn = (V, E) gegeben mit einer Gewichtsfunktion c : E → R+ . Das Problem des Handlungsreisenden (Traveling-Salesman-Problem, kurz TSP) besteht nun darin, eine Permutation n P π = (π1 , . . . , πn ) der Knoten zu finden, so dass die Gesamtkosten c(π) = cπi πi+1 (πn+1 = π1 ) der entsprechenden Tour minimal werden. Man kann verschiedene Typen von TSPs unterscheiden: i=1 • Wie man einfach sieht, ist das Hamilton-Kreis-Problem ein Spezialfall des TSP. • Beim metrischen TSP (∆TSP) erfüllen die Kanten des Graphen stets die Dreiecksungleichung, d.h. es gilt cij ≤ cih + chj für alle i, j, h ∈ V . Man kann zeigen, dass das metrische TSP N P-schwierig ist. • Beim asymmetrischen TSP (ATSP) liegen asymmetrische Kantenkosten vor, d.h. es gibt Knoten i, j ∈ V , so dass cij 6= cji . Da das TSP N P-vollständig ist, sind zumindest bei größeren Problemen exakte Lösungsverfahren kaum praktikabel. Daher ist eine Beschäftigung mit Näherungsverfahren sinnvoll, wobei wir als erstes einige einfache Heuristiken betrachten wollen. Bei allen vorgestellten Verfahren hat die Einfachheit der Algorithmen ihren Preis: Eine Gütegarantie für die Qualität der Lösungen, die man mit ihnen erhält, kann man nicht geben. Nearest-Neighbor-Heuristik: Diese Heuristik ist ein einfaches Greedy-Verfahren. Man startet mit einem beliebigen Knoten i1 ∈ V und fügt dann sukzessive den noch nicht besuchten Knoten ein, der zum vorher zur Tour hinzugefügten Knoten die geringste Distanz aufweist. Ist also eine Teiltour (i1 , . . . , ik ) gegeben, so fügt man nach ik den Knoten ik+1 ∈ V \ {i1 , . . . , ik } mit minimalen Kosten cik ik+1 zur Tour hinzu. Der große Nachteil dieses Verfahrens ist, dass man zum Ende häufig Kanten mit sehr hohen Kosten einfügen muss. Double-Nearest-Neighbor-Heuristik: Das Verfahren ist eine Erweiterung der Nearest-Neighbor-Heuristik. Statt den nächsten Knoten nur über die günstigsten Kosten der Kante vom zuletzt hinzugefügten Knoten zu ermitteln, sucht man einen Knoten ik , bei dem der Wert min{cik+1 i1 , cik ,ik+1 } minimal ist, und fügt ihn entsprechend vor i1 oder nach ik in die Tour ein. Nearest-Insertion-Heuristik: Wiederum startet man mit einem beliebigen Knoten i1 . In jedem Schritt fügt man anschließend den Knoten hinzu, der den geringsten Abstand zur bereits konstruierten Teiltour aufweist. Das Einfügen geschieht an der Stelle, an der es am günstigsten ist. Genauer: Ist bereits eine Teiltour (i1 , . . . , ik ) k © ª konstruiert, so ermittelt man den Knoten ik+1 , für den der Wert min ciν ik+1 ν=1 minimal ist. Anschließend fügt man ik+1 hinter einem Knoten il ein, so dass die Einfügekosten cil ik+1 + cik+1 il+1 − cil il+1 minimal sind. Farthest-Insertion-Heuristik: In dieser Heuristik kümmert man sich zuerst um die schwierigen Fälle“ d.h. die Knoten, die sehr weit von der bisher konstruierten ” Teiltour entfernt liegen. Man startet auch hier mit einem beliebigen Knoten und fügt in jedem Schritt den Knoten ik+1 zur bereits ermittelten Teiltour (i1 , . . . , ik ) ª k © hinzu, bei dem die Kosten max ciν ik+1 maximal sind. Das Einfügen selber geν=1 schieht analog zur Nearest-Insertion-Heuristik. Cheapest-Insertion-Heuristik: Startend mit einem beliebigen Knoten bestimmt man sukzessive den Knoten, der sich am günstigsten in die bereits konstruierte Teiltour einfügen lässt und fügt ihn an der entsprechenden Stelle ein. Ist also die Teiltour (i1 , . . . , ik ) konstruiert, so bestimmt man einen Knoten ik+1 , der minimale k © ª Kosten min ciν ik+1 + cik+1 iν+1 − ciν iν+1 aufweist. Anschließend fügt man ik+1 hinν=1 ter dem Knoten l in die Tour ein, für den das entsprechende Minimum angenommen wird. Programmieraufgabe Besuchen Sie die Internetseite http://www.iwr.uni-heidelberg.de/groups/comopt/software/TSPLIB95/. Dort findet man diverse Instanzen für unterschiedliche Varianten des TSP. Laden Sie sich die Dokumentation herunter und lesen sie die FAQ und die Dokumentation sorgfältig durch, im Verlaufe des Semesters wird stets auf Instanzen aus dieser Bibliothek oder weitere Instanzen im gleichen Format zurückgegriffen werden. Schreiben Sie anschließend ein C-Programm, das mittels einer Funktion readdata() explizit durch untere Dreiecksmatrizen mit Diagonalelementen vorgegebene TSPProbleme korrekt einlesen kann. Dies entspricht in den TSPLIB-Instanzen einem EDGE WEIGHT FORMAT von LOWER DIAG ROW. Mit Hilfe separater Funktionen sollen die Nearest-Neighbor, die Farthest-Insertion- und die Cheapest-Insertion-Heuristik implementiert werden, die Ansteuerung sowohl dieser Methoden als auch der readdata-Methode soll über eine Methode main() geschehen. Testen sie anschließend Ihr Programm mit den auf der Internetseite der Voranstaltung verfügbaren Instanzen rheinland.tsp und degbers1.tsp, die dem bekannten Rheinlandproblem und einem fiktiven Urlaub entsprechen, in dem der Praktikumsleiter einen Großteil seiner Freunde besuchen möchte. Geben sie die Ergebnisse in sinnvoller Form entweder in eine Datei oder auf die Kommandezeile aus. Sowohl der Dateiname der zu verarbeitenden Instanz als auch die zu verwendende Heuristik sollen nicht fest in den Programmcode geschrieben werden, sondern als Kommandozeilenargument oder über die Standardeingabe eingelesen werden. Gleiches gilt für die Ausgabedatei, wenn die Ergebnisse in eine solche geschrieben werden. Für die Ansteuerung der Heuristiken überlege man sich dabei sinnvolle Übergabeparameter, die bei Fehleingabe durch eine Funktion help() angezeigt werden, die aus der main-Methode automatisch aufgerufen wird. Der Speicherplatz für die verwendeten Datenstrukturen soll per calloc() oder malloc() automatisch vom Betriebssystem angefordert werden und zum Ende per free() freigegeben werden. Hinweis: Es ist empfehlenswert, zur Speicherung des TSP-Problems eine eigene Struktur zu verwenden.