Info zur Rückverfolgung
Transcription
Info zur Rückverfolgung
backtracking 1 Das Prinzip der Rückverfolgung - Tiefensuche Die griechische Mythologie erzählt von einem Labyrinth, indem der gefährliche Stier Minotaurus zu Hause war. Die verschlungene Bauweise sollte weder Mensch noch Bestie ein Entkommen gestatten. Doch Theseus gelang es mit Hilfe der Königstochter Ariadne nach einem Plan vorzugehen, der ihn zum Ausgang brachte. Ariadne kam auf die Idee, einen Faden am Eingang zu befestigen, den Theseus bei der Durchsuche des Labyrinthes nach dem Monster spannte und je nach Wegrichtung ab- bzw. aufrollte. Nachdem Theseus das Ungeheuer getötet hatte, brauchte er dem Faden nur noch rückwärts zu folgen, um aus dem Labyrinth in die Arme der geliebten Ariadne zu gelangen. Ein Algorithmus, wie der von Ariadne, mag nicht immer so lebenswichtig sein, nichtsdestoweniger hat er grundlegende Bedeutung in unterschiedlichen Situationen. Labyrinth ähnliche Situationen finden wir beispielsweise bei Stadtplänen mit ihren Straßen, bei Computernetzen z.B. im Internet, bei baumartigen Ahnentafeln, mit Baumknoten als Objekte. Verbindungsinformationen können zu allen Objekten definiert werden, zwischen denen Beziehungen existieren. Die Suche von Wegen durch ein Labyrinth steht damit stellvertretend für Algorithmen, welche die angesprochenen Beziehungen betreffen. Mit Aufgaben der oben dargestellten Art beschäftigt sich die Graphentheorie. Beim Labyrinthbeispiel verwenden wir allerdings die Begriffe der Graphentheorie noch nicht konsequent, sondern wenden uns dieser Formalisierung erst nach einer Beispiellösung zu. Terminologie und Eigenschaften Ein Labyrinth besteht aus Hallen und Gängen. Die Gänge sind vor- und rückwärts begehbar, also keine Einbahnstraßen. Wir bezeichnen sie als ungerichtet. In unserem ersten Zugang werden wir das Labyrinth in ein Rechteckgitter einteilen, dessen jede einzelne Zelle als Halle angesehen wird. Gänge liegen vor, wenn keine Wände zwischen zwei Nachbarzellen existieren. Auf dem Bildschirm wählen wir eine Zellengröße von 16 Punkten und horizontale und vertikale Linien als Trennsymbole. Das Bild zeigt mit den roten Punkten einen Weg von der linken oberen Ecke bis zur rechten unteren, dem Aufenthaltsort des Minotaurus. Die schwarzen Punkte hat Theseus beim Zurückgehen aus einer Sackgasse markiert, damit er nicht nochmals diesen Weg einschlägt. Theseus durchforstet das Labyrinth indem er in jeder Zelle erst versucht, Richtung Süden zu gehen, wenn der Versuch fehlschlägt Richtung Osten, dann Richtung Norden und schließlich Richtung Westen, allerdings jeweils nur, wenn er diesen Weg nicht bereits durchlaufen ist. Betrachte pro Situation jede theoretische Möglichkeit bzw. Richtung Falls die Möglichkeit akzeptabel, gehe einen Schritt in die Richtung und versuche die Lösung von hier aus zu finden Gehe den Schritt wieder zurück und versuche die Lösung mit der nächsten Möglichkeit Das Labyrinth-Problem Von einem Anfangspunkt (Eingang) aus ist über Labyrinthgänge ein Zielpunkt (Ausgang) zu erreichen. Implementierung import java.awt.*; import java.awt.event.*; import java.applet.*; public class Labyrinth extends Applet implements ActionListener { static final int anzx=15; static final int anzy=15; Button initB = new Button("Initialisieren"); Button startB = new Button("Das Ziel suchen"); Graphics g; Canvas can = new Canvas(); backtracking 2 boolean[][]V=new boolean[anzx][anzy]; boolean[][]H=new boolean[anzx][anzy]; boolean[][]Z=new boolean[anzx][anzy]; boolean problemGeloest = false; int startX, startY, zielX, zielY; Panel pN= new Panel(); Panel pZ= new Panel(); public void init() { resize(anzx*16+5,anzy*20+5); can.setSize(anzx*16+5,anzy*16+5); this.setLayout(new BorderLayout(5,5)); pN.add(initB); pN.add(startB); pZ.add(can); can.setBackground(Color.blue); this.add("North",pN); this.add("Center",pZ); initB.addActionListener(this); startB.addActionListener(this); } public void actionPerformed(ActionEvent e) { Object quelle = e.getSource(); if (quelle == initB) { initialisiere(); g = can.getGraphics(); zeichneLabyrinth(g); } else if (quelle == startB) { problemGeloest = false; backtracking(new Punkt(0,0)); g.dispose(); } } //actionPerformed void initialisiere() { //zufällige Erzeugung des Labyrinths } //initialisiere void zeichneLabyrinth(Graphics g) { g.setColor(Color.blue); g.fillRect(0,0,this.getWidth(),this.getHeight()); //usw. } void plottH(int i,int k, Graphics g) { g.setColor(Color.yellow); g.drawLine(5+16*i,5+16*k,5+16*i+16,5+16*k); } void plottV(int i,int k, Graphics g) { g.setColor(Color.yellow); g.drawLine(5+16*i,5+16*k,5+16*i,5+16*k+16); } void plottZ(int i, int k, Graphics g) { g.setColor(Color.red); g.fillOval(5+16*i+4,5+16*k+4,8,8); } void replottZ(int i, int k, Graphics g) { g.setColor(Color.blue); g.fillOval(5+16*i+4,5+16*k+4,8,8); } //----------------------------boolean imSuedenOffen(int x, int y) { return H[x][y+1];} boolean imOstenOffen(int x, int y) { return V[x+1][y];} boolean imNordenOffen(int x, int y) { return H[x][y];} boolean imWestenOffen(int x, int y) { return V[x][y];} boolean imZiel(int x, int y) { return ((zielX == x) && (zielY == y));} backtracking // } // Labyrinth class Punkt { int x; int y; Punkt(int x, int y) { this.x = x; this.y = y; } } 3