Ceci est un exemple de ce que je veux faire via du code. Je sais que vous pouvez utiliser la recherche de points de saut pour passer facilement du nœud vert au nœud rouge sans problème, ou même A *. Mais comment calculer cela avec des chaînes.
Dans l'image, vous pouvez voir qu'il ne faut que 8 mouvements pour passer du nœud vert au nœud rouge lors de la prise du chemin bleu. Le chemin bleu déplace instantanément votre position d'un nœud violet au suivant. L'espace au milieu qui coûte 2 mouvements est un point entre deux zones de distorsion que vous devez déplacer pour y accéder.
Il est clairement plus rapide de prendre le chemin bleu, car il suffit de se déplacer à peu près (à peu près) jusqu'au chemin jaune, mais comment faire par programme?
Pour résoudre ce problème, supposons qu'il existe plusieurs "déformations" violettes autour du graphique que vous pouvez utiliser, ET nous savons exactement où chaque point violet se déformera et où elles se trouvent sur le graphique.
Certaines chaînes violettes sont bidirectionnelles et d'autres non, ce qui signifie que parfois vous ne pouvez entrer dans une chaîne que d'un côté, mais pas revenir en arrière après la déformation.
J'ai réfléchi à la solution et j'ai seulement conclu que je serais en mesure de calculer le problème en vérifiant la distance à chaque point de distorsion (moins les points unidirectionnels), et la différence entre ces points et les points proches d'eux .
Le programme devrait comprendre d'une manière ou d'une autre qu'il est plus avantageux de prendre la deuxième chaîne, plutôt que de marcher depuis le premier saut. Donc, au lieu de déplacer 6 points, puis de déformer, puis de déplacer les 8 étapes restantes à pied (ce qui est également plus rapide que de ne pas utiliser de chaînes du tout), il faudrait les 6 mouvements, puis les deux mouvements vers la deuxième chaîne.
EDIT: J'ai réalisé que le chemin bleu prendra en fait 12 coups, au lieu de 8, mais la question reste la même.
la source
Réponses:
La plupart des algorithmes de recherche de chemin sont définis en termes de graphiques, pas en termes de grilles. Dans un graphique, une connexion entre deux nœuds autrement distants n'est pas vraiment un problème.
Cependant, vous devez faire attention à votre heuristique. Avec les trous de ver, la distance minimale entre deux nœuds n'est plus la distance euclidienne et la distance ne satisfait pas l'inégalité du triangle. De telles heuristiques sont inadmissibles pour A *. Vous ne pouvez donc pas utiliser facilement A *.
Bien sûr, les algorithmes de recherche de chemin comme Dijkstra qui n'utilisent pas d'heuristique fonctionneront toujours. Cela ressemble plus à une recherche en largeur et sélectionnera vos trous de ver sans effort supplémentaire. Cependant, Dijkstra visitera plus de nœuds que A * avec une bonne heuristique. (Dijkstra est équivalent à A * avec
heuristic(x) = 0
.)Je pense que A * fonctionnera si vous utilisez une heuristique qui traite tous les trous de ver sortants comme un trou de ver directement sur la cible: l'heuristique peut sous-estimer la distance, mais ne doit jamais la surestimer. C'est-à-dire que l'heuristique serait:
Pour une heuristique très précise, vous pouvez (récursivement) ajouter la distance entre le point d'extrémité du trou de ver et l'objectif ou le trou de ver suivant. C'est-à-dire qu'en tant que pré-calcul, vous pouvez effectuer la recherche de chemin sur le sous-graphique (totalement connecté) contenant tous les trous de ver et l'objectif, où la distance entre deux nœuds est leur distance euclidienne. Cela peut être bénéfique si le nombre de trous de ver est bien inférieur au nombre de cellules accessibles sur votre grille. La nouvelle heuristique serait:
Comme @Caleth le souligne dans les commentaires, tout cela est très ajustable et nous pouvons améliorer la première heuristique de trou de ver sans faire une recherche de chemin complète à travers le réseau de trou de ver, en ajoutant la distance entre la dernière sortie de trou de ver et l'objectif. Parce que nous ne savons pas quelle sortie de trou de ver sera utilisée en dernier et que nous ne devons pas surestimer, nous devons supposer la sortie la plus proche de l'objectif:
la source
dijkstra_heuristic(x) = 0
wormhole_path_distance
que la recherche sous-graphique, et moins sous-estimée que "toutes les sorties sont sur le but".Vous avez un graphe à 6 sommets sur une grille avec des coordonnées:
Vous pouvez générer un graphique complet sur ces sommets et attribuer un coût à chaque bord où le coût est
MAX( ABS( x1 - x2 ), ABS( y1 - y2 ) )
pour les bords standard et un coût de 0 pour les trous de ver.Cela vous donnera les coûts (en tant que matrice d'adjacence):
S'il y a des déformations unidirectionnelles, créez uniquement des arêtes dans le graphique (ou la matrice d'adjacence) qui vont dans cette direction mais pas dans le sens opposé.
Vous pouvez ensuite utiliser l'algorithme de Dijkstra avec une file d'attente prioritaire .
Commencez par
A
et poussez chaque bord adjacent sur la file d'attente prioritaire:Format: (chemin: coût)
Au fur et à mesure que les éléments sont poussés dans la file d'attente - gardez une trace du coût minimum pour chaque sommet et ne poussez les chemins dans la file d'attente que si leur coût est inférieur au coût minimum existant.
Supprimez le premier élément de la file d'attente et, si son coût correspond toujours au coût minimum, repoussez tous les chemins composites formés par ce chemin et ses bords adjacents dans la file d'attente prioritaire (si les chemins composites ont un coût inférieur au minimum existant):
Retirer:
(A-B : 7)
(A-B-A : 14)
- rejeter comme coût plus élevé(A-B-C : 7)
- rejeter au même coût(A-B-D : 13)
- rejeter comme coût plus élevé(A-B-E : 19)
- rejeter comme coût plus élevé(A-B-F : 19)
- rejeter comme coût plus élevéRetirer
(A-C : 7)
(A-C-A : 14)
- rejeter comme coût plus élevé(A-C-B : 7)
- rejeter au même coût(A-C-D : 10)
- rejeter au même coût(A-C-E : 16)
- rejeter au même coût(A-C-F : 16)
- rejeter au même coûtRetirer
(A-D : 10)
(A-D-A : 20)
- rejeter comme coût plus élevé(A-D-B : 16)
- rejeter comme coût plus élevé(A-D-C : 13)
- rejeter comme coût plus élevé(A-D-E : 10)
- insérer dans la file d'attente(A-D-F : 16)
- rejeter au même coûtMaintenant, la file d'attente ressemblera à:
Retirer
(A-D-E : 10)
(A-D-E-A : 26)
- rejeter comme coût plus élevé(A-D-E-B : 22)
- rejeter comme coût plus élevé(A-D-E-C : 19)
- rejeter comme coût plus élevé(A-D-E-D : 10)
- rejeter au même coût(A-D-E-F : 12)
- insérer dans la file d'attenteEnsuite, la file d'attente est:
Supprimez
(A-D-E-F : 12)
, trouvez que vous êtes arrivé au nœud de destination au coût de 12.Remarque: les chemins
(A-B-C-D-E-F)
,(A-C-D-E-F)
et(A-D-E-F)
tous ont le même coût minimum de 12.la source
Configurez une matrice contenant tous les sommets et utilisez l'algorithme Floyd-Wallenstein ou l'algorithme Bellman-Ford. Les deux résulteront en une matrice avec les chemins les plus courts possibles entre tous les points. Vous pouvez ensuite parcourir la matrice pour trouver le chemin le plus court reliant deux points. (votre problème est le même qu'un TSP asymétrique).
la source