Wie finde ich den kürzesten Weg mit Wurmlochknoten?

25

Beispiel

Dies ist ein Beispiel dafür, was ich per Code tun möchte. Ich weiß, dass Sie die Sprungpunktsuche verwenden können, um problemlos vom grünen Knoten zum roten Knoten oder sogar zu A * zu gelangen. Aber wie rechnet man das mit Warps?

Im Bild können Sie sehen, dass es nur 8 Züge dauert, um vom grünen zum roten Knoten zu gelangen, wenn Sie den blauen Pfad nehmen. Der blaue Pfad verschiebt Ihre Position sofort von einem lila Knoten zum nächsten. Das Feld in der Mitte, das 2 Züge kostet, ist ein Punkt zwischen zwei Warpzonen, zu dem Sie sich bewegen müssen, um zu gelangen.

Es ist deutlich schneller, den blauen Pfad einzuschlagen, da Sie nur die Hälfte (ungefähr) bis zum gelben Pfad zurücklegen müssen. Wie mache ich das programmgesteuert?

Um dieses Problem zu lösen, nehmen wir an, dass das Diagramm mehrere violette "Verzerrungen" enthält, die Sie verwenden können, UND wir wissen genau, wohin sich die einzelnen violetten Punkte verzerren und wo sie sich im Diagramm befinden.

Einige violette Verzerrungen sind bidirektional und andere nicht, was bedeutet, dass Sie eine Verzerrung manchmal nur von einer Seite eingeben können, nach dem Verzerren jedoch nicht zurück.

Ich habe über die Lösung nachgedacht und bin nur zu dem Schluss gekommen, dass ich das Problem berechnen kann, indem ich den Abstand zu jedem Warp-Punkt (abzüglich der unidirektionalen Punkte) und den Unterschied zwischen diesen Punkten und den nahegelegenen Punkten überprüfe .

Das Programm müsste irgendwie herausfinden, dass es vorteilhafter ist, den zweiten Warp auszuführen, anstatt vom ersten Sprung zu laufen. Anstatt also 6 Punkte zu bewegen, dann zu verziehen und dann die restlichen 8 Schritte zu Fuß zu bewegen (was auch schneller ist, als überhaupt keine Verzerrungen zu verwenden), würden die 6 Züge und dann die beiden Züge zur zweiten Verzerrung führen.

EDIT: Ich habe festgestellt, dass der blaue Pfad tatsächlich 12 statt 8 Züge benötigt, aber die Frage bleibt dieselbe.

Jeff Smith
quelle
4
Sollte der blaue Pfad nicht 12 sein (einschließlich der beiden, um vom letzten Purpur zum roten zu gelangen)?
BlueRaja - Danny Pflughoeft
5
Blau ist eigentlich 12 (7 + 3 + 2) Züge, nein?
Daniel Jour
Ups, durcheinander, danke Jungs! @ DanielJour und Blue
Jeff Smith
Die "richtige" Art, die Entfernungen zu modellieren, besteht darin, die Topologie zu verwenden und diese als höherdimensionale Oberfläche zu modellieren. Ich frage mich, ob eine solche Antwort hier angemessen wäre.
Geeky ich

Antworten:

49

Die meisten Pfadsuchalgorithmen werden in Form von Diagrammen und nicht in Form von Gittern definiert. In einem Graphen ist eine Verbindung zwischen zwei ansonsten entfernten Knoten nicht wirklich ein Problem.

Sie müssen jedoch auf Ihre Heuristiken achten. Bei Wurmlöchern entspricht der Mindestabstand zwischen zwei Knoten nicht mehr dem euklidischen Abstand und der Abstand entspricht nicht mehr der Dreiecksungleichung. Solche Heuristiken sind für A * unzulässig. Sie können daher A * nicht einfach verwenden.

Natürlich funktionieren auch Pfadfindungsalgorithmen wie Dijkstra, die keine Heuristik verwenden. Dies ist eher eine Breitensuche und wählt Ihre Wurmlöcher ohne zusätzlichen Aufwand aus. Dijkstra wird jedoch mehr Knoten als A * mit einer guten Heuristik besuchen. (Dijkstra entspricht A * mit heuristic(x) = 0.)

Ich denke, A * wird funktionieren, wenn Sie eine Heuristik verwenden, die alle ausgehenden Wurmlöcher als Wurmloch direkt zum Ziel behandelt: Die Heuristik kann die Entfernung unterschätzen, darf sie jedoch niemals überschätzen. Dh die Heuristik wäre:

def wormhole_heuristic(x):
  return min(euclidean_distance(x, g) for g in [goal, wormholes...])

Für eine sehr genaue Heuristik können Sie (rekursiv) den Abstand vom Endpunkt des Wurmlochs zum Ziel oder zum nächsten Wurmloch hinzufügen. Dh als Vorberechnung können Sie die Wegfindung auf dem (vollständig verbundenen) Teilgraphen durchführen, der alle Wurmlöcher und das Ziel enthält, wobei der Abstand zwischen zwei Knoten der euklidische Abstand ist. Dies kann von Vorteil sein, wenn die Anzahl der Wurmlöcher weit unter der Anzahl der erreichbaren Zellen in Ihrem Raster liegt. Die neue Heuristik wäre:

def wormhole_heuristic(x):
  direct = euclidean_distance(x, goal)
  via_wormhole = min(euclidean_distance(x, w) + wormhole_path_distance(w, goal) for w in wormholes)
  return min(direct, via_wormhole)

Wie @Caleth in den Kommentaren ausführt, ist dies alles sehr gut einstellbar und wir können die Heuristik des ersten Wurmlochs verbessern, ohne einen vollständigen Weg durch das Wurmlochnetz zu finden, indem wir den Abstand zwischen dem letzten Wurmlochausgang und dem Ziel addieren. Da wir nicht wissen, welcher Wurmloch-Ausgang zuletzt verwendet wird und wir nicht überschätzen dürfen, müssen wir den Ausgang annehmen, der dem Ziel am nächsten liegt:

def wormhole_heuristic(x):
  direct = euclidean_distance(x, goal)
  to_next_wormhole = min(euclidean_distance(x, w) for w in wormholes)
  from_last_wormhole = min(euclidean_distance(w.exit, goal) for w in wormholes)
  via_wormhole = to_next_wormhole + from_last_wormhole
  return min(direct, via_wormhole)
amon
quelle
10
Erwähnenswert ist, dass Dijkstra nur A * mitdijkstra_heuristic(x) = 0
Caleth
Ich verstehe nicht, was du mit [* Wurmlöcher, Ziel] meinst, würdest du das erklären?
Jeff Smith
1
"Euklidische Entfernung zum nächsten Wurmlochausgang" ist eine günstigere Schätzung wormhole_path_distanceals die Subgraphen-Suche und weniger unterschätzt als die "Alle Ausgänge sind auf dem Ziel".
Caleth
3
@Caleth sicherlich! Hier gibt es viel Potenzial zur Feinabstimmung, z. B. könnten wir uns für n = 3 Sprünge entscheiden. Die Subgraphensuche entspricht dem Abschluss aller azyklischen Wurmlochsprünge. Ihr Vorschlag, n = 1 Sprünge nach vorne zu schauen, ist sehr elegant, da es im Grunde keine zusätzlichen Kosten verursacht :)
amon
1
Nehmen Sie der Einfachheit halber an, dass es nur ein Wurmloch gibt (zwei Knoten). Dann können Sie dieses ebene 1-Wurmloch in zwei Spiegelebenen umwandeln, indem Sie eine symmetrische Ebene mit der äquidistanten Linie zwischen diesen beiden Punkten als Symmetrieachse kopieren. Sie haben jetzt zwei Ebenen, nennen wir sie die reale Ebene (Sie nehmen nicht das Wurmloch) und die imaginäre Ebene (Sie haben das Wurmloch genommen). Nun führen wir die Z-Koordinate ein. Diese Koordinate ist 0 für jeden Punkt in der realen Ebene und dist (Wurmloch, Punkt) für jeden Punkt der imaginären Ebene. Wenden Sie danach A * für den dreidimensionalen Raum an.
Lilezek
5

Sie haben ein Diagramm mit 6 Eckpunkten in einem Gitter mit Koordinaten:

A ( 0,0)
B ( 4,7)
C ( 7,4)
D (10,4)
E (16,2)
F (16,0)

Sie können ein vollständiges Diagramm für diese Eckpunkte erstellen und jeder Kante Kosten zuweisen, wobei die Kosten MAX( ABS( x1 - x2 ), ABS( y1 - y2 ) )für Standardkanten und die Kosten für Wurmlöcher 0 betragen.

Dies gibt Ihnen die Kosten (als Adjazenzmatrix):

   A  B  C  D  E  F
- -- -- -- -- -- --
A  -  7  7 10 16 16
B  7  -  0  6 12 12
C  7  0  -  3  9  9
D 10  6  3  -  0  6
E 16 12  9  0  -  2
F 16 12  9  6  2  -

Wenn es einseitige Verzerrungen gibt, erstellen Sie nur Kanten in der Grafik (oder der Adjazenzmatrix), die in diese Richtung verlaufen, jedoch nicht in die entgegengesetzte Richtung.

Sie können dann den Dijkstra-Algorithmus mit einer Prioritätswarteschlange verwenden .

Beginnen Sie mit Aund verschieben Sie jede benachbarte Kante in die Prioritätswarteschlange:

Format: (Pfad: Kosten)

queue     = [ (A-B : 7), (A-C : 7), (A-D : 10), (A-E : 16), (A-F : 16) ]

Wenn die Elemente in die Warteschlange verschoben werden, behalten Sie die Mindestkosten für jeden Scheitelpunkt im Auge und verschieben Sie Pfade nur dann in die Warteschlange, wenn die Kosten niedriger sind als die vorhandenen Mindestkosten.

min-costs = { A: 0, B: 7, C: 7, D: 10, E: 16, F: 16 }

Entfernen Sie das erste Element aus der Warteschlange, und verschieben Sie alle zusammengesetzten Pfade, die von diesem Pfad und den angrenzenden Kanten gebildet werden, in die Prioritätswarteschlange zurück, wenn die zusammengesetzten Pfade niedrigere Kosten als das vorhandene Minimum haben.

Löschen: (A-B : 7)

  • Versuchen Sie (A-B-A : 14)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-B-C : 7)- als gleiche Kosten abzulehnen
  • Versuchen Sie (A-B-D : 13)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-B-E : 19)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-B-F : 19)- als höhere Kosten abzulehnen

Löschen (A-C : 7)

  • Versuchen Sie (A-C-A : 14)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-C-B : 7)- als gleiche Kosten abzulehnen
  • Versuchen Sie (A-C-D : 10)- als gleiche Kosten abzulehnen
  • Versuchen Sie (A-C-E : 16)- als gleiche Kosten abzulehnen
  • Versuchen Sie (A-C-F : 16)- als gleiche Kosten abzulehnen

Löschen (A-D : 10)

  • Versuchen Sie (A-D-A : 20)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-D-B : 16)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-D-C : 13)- als höhere Kosten abzulehnen
  • Versuch (A-D-E : 10)- Einfügen in die Warteschlange
  • Versuchen Sie (A-D-F : 16)- als gleiche Kosten abzulehnen

Jetzt sieht die Warteschlange so aus:

queue     = [ (A-D-E : 10), (A-E : 16), (A-F : 16) ]
min-costs = { A: 0, B: 7, C: 7, D: 10, E: 10, F: 16 }

Löschen (A-D-E : 10)

  • Versuchen Sie (A-D-E-A : 26)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-D-E-B : 22)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-D-E-C : 19)- als höhere Kosten abzulehnen
  • Versuchen Sie (A-D-E-D : 10)- als gleiche Kosten abzulehnen
  • Versuch (A-D-E-F : 12)- Einfügen in die Warteschlange

Dann ist die Warteschlange:

queue     = [ (A-D-E-F : 12), (A-E : 16), (A-F : 16) ]
min-costs = { A: 0, B: 7, C: 7, D: 10, E: 10, F: 12 }

Entfernen (A-D-E-F : 12)Sie, und stellen Sie fest, dass Sie zum Zielknoten gekommen sind (Kosten 12).

Hinweis: die Pfade (A-B-C-D-E-F), (A-C-D-E-F)und (A-D-E-F)alle haben den gleichen minimalen Kosten von 12.

MT0
quelle
0

Stellen Sie eine Matrix mit allen Eckpunkten auf und verwenden Sie den Floyd-Wallenstein-Algorithmus oder den Bellman-Ford-Algorithmus. Beides ergibt eine Matrix mit möglichst kurzen Wegen zwischen allen Punkten. Sie können dann durch die Matrix iterieren, um den kürzesten Pfad zu finden, der zwei Punkte verbindet. (Ihr Problem ist dasselbe wie bei einem asymmetrischen TSP).

Rene
quelle