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