web-dev-qa-db-fra.com

Comment calculer le chemin le plus court entre deux points d'une grille

Je sais que de nombreux algorithmes sont disponibles pour calculer le chemin le plus court entre deux points dans un graphique ou une grille, comme l'étendue en premier, toutes les paires (Floyd), Dijkstra.

Cependant, comme je l'ai remarqué, tous ces algorithmes calculent tous les chemins dans ce graphique ou cette grille, pas seulement ceux entre les deux points qui nous intéressent.

MA QUESTION EST: si j'ai une grille, c'est-à-dire un tableau à deux dimensions, et que je suis intéressé à calculer le chemin le plus court entre deux points, disons P1 et P2, et s'il y a des restrictions sur la façon dont je peux me déplacer sur la grille (par exemple uniquement en diagonale, ou uniquement en diagonale et vers le haut, etc.), quel algorithme peut calculer cela?

Veuillez noter ici que si vous avez une réponse, je voudrais que vous affichiez le nom de l'algorithme plutôt que l'algorithme lui-même (bien sûr, encore mieux si vous publiez également l'algorithme); par exemple, s'il s'agit L'algorithme de Dijkstra, ou Floyd, ou autre chose.

S'il vous plaît, aidez-moi, j'y pense depuis des mois!


ok les gars, j'ai trouvé cet algorithme sur TOPCODER.COM ici dans la grille, vous ne pouvez vous déplacer que (en diagonale et vers le haut) mais je ne peux pas comprendre de quel algorithme s'agit-il, est-ce que quelqu'un pourrait le savoir?

#include<iostream>
#include <cmath>

using namespace std;




inline int Calc(int x,int y)

{



if(abs(x)>=abs(y)) return abs(x);
int z=(abs(x)+abs(y))/2;
return z+abs(abs(x)-z);
 }

class SliverDistance
{


    public:
int minSteps(int x1,int y1, int x2, int y2)
{
    int ret=0;
    if(((x1+y1)&1)!=((x2+y2)&1))y1++,ret++;
    return ret+Calc(x2-x1,y2-y1);
}
};
33
Alan_AI

Algorithme de Lee: http://en.wikipedia.org/wiki/Lee_algorithm

Il s'agit essentiellement d'une recherche BF, voici un exemple: http://www.oop.rwth-aachen.de/documents/oop-2007/sss-oop-2007.pdf

Pour l'implémenter efficacement, vérifiez ma réponse ici: Changer FloodFill-Algorithm pour obtenir Voronoi Territory pour deux points de données? - quand je dis marque, vous le marquez avec le numéro sur la position d'où vous venez + 1 .

Par exemple, si vous avez cette grille, où un * = obstacle et vous pouvez vous déplacer vers le haut, le bas, la gauche et la droite, et vous partez de S et devez aller à D, et 0 = position libre:

S 0 0 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

Vous mettez S dans votre file d'attente, puis vous "développez":

S 1 0 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

Développez ensuite tous ses voisins:

S 1 2 0
* * 0 *
* 0 0 *
0 0 * *
* 0 0 D

Et tous les voisins de ces voisins:

S 1 2 3
* * 3 *
* 0 0 *
0 0 * *
* 0 0 D

Et ainsi de suite, à la fin, vous obtiendrez:

S 1 2 3
* * 3 *
* 5 4 *
7 6 * *
* 7 8 9

La distance de S à D est donc de 9. Le temps d'exécution est O (NM), où N = nombre de lignes et M = nombre de colonnes. Je pense que c'est l'algorithme le plus facile à implémenter sur les grilles, et il est également très efficace dans la pratique. Il devrait être plus rapide qu'un dijkstra classique, bien que dijkstra puisse gagner si vous l'implémentez en utilisant des tas.

40
IVlad

Utilisez l'algorithme A Star (A *) .

6
newdayrising

Vous pourriez être mal informé. Il existe différentes variantes de l'algorithme de Dijkstra. On calcule les chemins les plus courts de chaque point à tous les autres points (comme celui de Floyd).

Cependant, l'algorithme Dijkstra typique est basé sur une file d'attente prioritaire et ne calcule que le chemin le plus court requis. Il construit plusieurs chemins lors de son exécution, mais ce sont tous des chemins partiels de A vers d'autres nœuds qui pourraient se trouver sur le chemin de la solution finale.

Par conséquent, vous pouvez facilement interpréter votre grille comme un graphique (les restrictions comme les diagonales peuvent ensuite être prises en compte en conséquence) et lancer une recherche Dijkstra pour le chemin le plus court de A à B là-dessus. C'est vraiment juste une question de modélisation de votre problème, pas que vous ayez besoin d'un algorithme sophistiqué.

5
Frank

Si votre mouvement est suffisamment restrictif (par exemple, vous ne pouvez vous déplacer que vers la droite, ou vers le haut, ou vers la diagonale vers le haut et vers la droite), alors vous pouvez exploiter ses sous-problèmes qui se chevauchent et sa nature de sous-structure optimale et utiliser programmation dynamique .

2
polygenelubricants

Voici une implémentation python du chemin le plus court dans une matrice de (0,0) à (0, m-1) en utilisant BFS. Vous pouvez le modifier pour l'adapter à des points variables.

n,m,k1,k2=[int(i) for i in input().split()]
arr=[[int(j) for j in input().split()] for i in range(n)]
x=[[-1 for i in range(m)] for j in range(n)]
x[0][0]=0
vis={}
q=[(0,0)]
while len(q)!=0:
    curr=q[0]
    rem=q.pop(0)
    vis[curr]=True
    r=curr[0]
    c=curr[1]
    if r-1>=0 and arr[r-1][c]==0:
        if vis.get((r-1,c),-1)==-1 or vis[(r-1,c)]!=True:
            q.append((r-1,c))
            x[r-1][c]=x[r][c]+1
    if r+1<n and arr[r+1][c]==0:
        if vis.get((r+1,c),-1)==-1 or vis[(r+1,c)]!=True:
            q.append((r+1,c))
            x[r+1][c]=x[r][c]+1
    if c-1>=0 and arr[r][c-1]==0:
        if vis.get((r,c-1),-1)==-1 or vis[(r,c-1)]!=True:
            q.append((r,c-1))
            x[r][c-1]=x[r][c]+1
    if c+1<m and arr[r][c+1]==0:
        if vis.get((r,c+1),-1)==-1 or vis[(r,c+1)]!=True:
            q.append((r,c+1))
            x[r][c+1]=x[r][c]+1
    #for i in x:
        #print(i)
ans=x[0][m-1]
if ans==-1:
    print(-1)
else:
    print(ans)
  • la matrice d'entrée doit être composée de 0 et de 1. 0 est pour un mouvement possible.
  • n est le nombre de lignes.
  • m est le nombre de colonnes.
  • arr est la matrice donnée.
  • x est la matrice de distance de (0,0).
  • vis est un dictionnaire donnant un booléen si le nœud est visité.
  • la sortie de -1 montre qu'il n'y a pas de chemin possible.
1
Apurv

Ce que je ne comprends pas, c'est que si vous voulez le chemin le plus court entre A et B, n'avez-vous pas encore besoin de regarder A vers C et A vers D si C et D pointent vers B? Votre chemin le plus court pourrait très bien être A-C-B ou A-D-B. Vous avez juste besoin de jeter les nœuds non connectés. Dans l'un de mes projets, j'ai pris les points A et B, vérifié pour voir quels autres points étaient connectés et ceux qui ne l'étaient pas ont été supprimés de l'ensemble du graphique. Ensuite, j'ai continué à utiliser l'algorithme de Dijkstra.

1
Dave

Votre grille forme un graphique (ou du moins peut être visualisée sous forme de graphique). L'élimination de certaines directions de mouvement indique qu'il s'agit d'un graphique dirigé. Si vous ne pouvez pas passer d'un nœud à un autre, c'est un Edge qui n'est pas présent dans le graphique.

Une fois que vous avez encodé votre grille sous forme de graphique, il vous suffit de sélectionner parmi les algorithmes de graphique bien connus (dont vous êtes apparemment déjà au courant) pour la parcourir pour le type de résultat souhaité (par exemple, le chemin le plus court).

Edit: J'ai regardé la réponse que vous avez postée, mais je ne suis pas sûr de ce que ce code est censé être/faire. Par exemple, il a: if(y>=0) max(abs(x),y);. Cela ne semble pas (du moins pour moi) avoir beaucoup de sens - le résultat de max est simplement jeté. Pour accomplir quelque chose d'utile, il doit être retourné ou attribué ou quelque chose sur cette commande. En l'état, le mieux que vous puissiez espérer est que le compilateur le repère comme du code mort et ne génère rien pour cela.

Je suppose que le code ne fonctionne pas vraiment comme prévu, et s'il fait quelque chose d'utile, c'est plus par accident que par conception. Il faudrait beaucoup de temps et d'efforts pour être sûr d'avoir réglé les problèmes comme celui-ci au point que vous étiez vraiment sûr de ce qu'il a fait, et encore plus difficile de deviner ce qui était vraiment prévu.

0
Jerry Coffin