web-dev-qa-db-fra.com

Java - Trouver le chemin le plus court entre 2 points dans une carte pondérée par la distance

J'ai besoin d'un algorithme pour trouver le chemin le plus court entre deux points sur une carte où la distance de la route est indiquée par un nombre.

ce qui est donné: Ville de départ A Ville de destination Z

Liste des distances entre les villes:

A - B: 10
F - K: 23
R - M: 8
K - O: 40
Z - P: 18
J - K: 25
D - B: 11
M - A: 8
P - R: 15

Je pensais pouvoir utiliser l'algorithme de Dijkstra, mais il trouve la distance la plus courte vers toutes les destinations. pas seulement un.

Toute suggestion est appréciée.

11
sanjan

Comme SplinterReality l'a dit: There's no reason not to use Dijkstra's algorithm here.

Le code ci-dessous a été extrait de ici et l'a modifié pour résoudre l'exemple de la question.

import Java.util.PriorityQueue;
import Java.util.List;
import Java.util.ArrayList;
import Java.util.Collections;

class Vertex implements Comparable<Vertex>
{
    public final String name;
    public Edge[] adjacencies;
    public double minDistance = Double.POSITIVE_INFINITY;
    public Vertex previous;
    public Vertex(String argName) { name = argName; }
    public String toString() { return name; }
    public int compareTo(Vertex other)
    {
        return Double.compare(minDistance, other.minDistance);
    }

}


class Edge
{
    public final Vertex target;
    public final double weight;
    public Edge(Vertex argTarget, double argWeight)
    { target = argTarget; weight = argWeight; }
}

public class Dijkstra
{
    public static void computePaths(Vertex source)
    {
        source.minDistance = 0.;
        PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
        vertexQueue.add(source);

        while (!vertexQueue.isEmpty()) {
            Vertex u = vertexQueue.poll();

            // Visit each Edge exiting u
            for (Edge e : u.adjacencies)
            {
                Vertex v = e.target;
                double weight = e.weight;
                double distanceThroughU = u.minDistance + weight;
                if (distanceThroughU < v.minDistance) {
                    vertexQueue.remove(v);

                    v.minDistance = distanceThroughU ;
                    v.previous = u;
                    vertexQueue.add(v);
                }
            }
        }
    }

    public static List<Vertex> getShortestPathTo(Vertex target)
    {
        List<Vertex> path = new ArrayList<Vertex>();
        for (Vertex vertex = target; vertex != null; vertex = vertex.previous)
            path.add(vertex);

        Collections.reverse(path);
        return path;
    }

    public static void main(String[] args)
    {
        // mark all the vertices 
        Vertex A = new Vertex("A");
        Vertex B = new Vertex("B");
        Vertex D = new Vertex("D");
        Vertex F = new Vertex("F");
        Vertex K = new Vertex("K");
        Vertex J = new Vertex("J");
        Vertex M = new Vertex("M");
        Vertex O = new Vertex("O");
        Vertex P = new Vertex("P");
        Vertex R = new Vertex("R");
        Vertex Z = new Vertex("Z");

        // set the edges and weight
        A.adjacencies = new Edge[]{ new Edge(M, 8) };
        B.adjacencies = new Edge[]{ new Edge(D, 11) };
        D.adjacencies = new Edge[]{ new Edge(B, 11) };
        F.adjacencies = new Edge[]{ new Edge(K, 23) };
        K.adjacencies = new Edge[]{ new Edge(O, 40) };
        J.adjacencies = new Edge[]{ new Edge(K, 25) };
        M.adjacencies = new Edge[]{ new Edge(R, 8) };
        O.adjacencies = new Edge[]{ new Edge(K, 40) };
        P.adjacencies = new Edge[]{ new Edge(Z, 18) };
        R.adjacencies = new Edge[]{ new Edge(P, 15) };
        Z.adjacencies = new Edge[]{ new Edge(P, 18) };


        computePaths(A); // run Dijkstra
        System.out.println("Distance to " + Z + ": " + Z.minDistance);
        List<Vertex> path = getShortestPathTo(Z);
        System.out.println("Path: " + path);
    }
}

Le code ci-dessus produit:

Distance to Z: 49.0
Path: [A, M, R, P, Z]
35
luke

Sanjan estimé:

L'idée derrière l'algorithme de Dijkstra est d'explorer tous les nœuds du graphique de manière ordonnée. L'algorithme stocke une file d'attente prioritaire où les nœuds sont ordonnés en fonction du coût depuis le début, et à chaque itération de l'algorithme, les opérations suivantes sont effectuées:

  1. Extraire de la file d'attente le nœud le moins cher dès le départ, N
  2. Obtenir ses voisins (N ') et leur coût associé, qui est coût (N) + coût (N, N')
  3. Insérer en file d'attente les nœuds voisins N ', avec la priorité donnée par leur coût

Il est vrai que l'algorithme calcule le coût du chemin entre le début (A dans votre cas) et tous les autres nœuds, mais vous pouvez arrêter l'exploration de l'algorithme lorsqu'il atteint l'objectif (Z dans votre exemple). À ce stade, vous connaissez le coût entre A et Z et le chemin qui les relie.

Je vous recommande d'utiliser une bibliothèque qui implémente cet algorithme au lieu de coder le vôtre. En Java, vous pouvez jeter un œil à la bibliothèque Hipster , qui a un moyen très convivial pour générer le graphique et commencer à utiliser les algorithmes de recherche.

Ici, vous avez un exemple de la façon de définir le graphique et de commencer à utiliser Dijstra avec Hipster.

// Create a simple weighted directed graph with Hipster where
// vertices are Strings and Edge values are just doubles
HipsterDirectedGraph<String,Double> graph = GraphBuilder.create()
  .connect("A").to("B").withEdge(4d)
  .connect("A").to("C").withEdge(2d)
  .connect("B").to("C").withEdge(5d)
  .connect("B").to("D").withEdge(10d)
  .connect("C").to("E").withEdge(3d)
  .connect("D").to("F").withEdge(11d)
  .connect("E").to("D").withEdge(4d)
  .buildDirectedGraph();

// Create the search problem. For graph problems, just use
// the GraphSearchProblem util class to generate the problem with ease.
SearchProblem p = GraphSearchProblem
  .startingFrom("A")
  .in(graph)
  .takeCostsFromEdges()
  .build();

// Search the shortest path from "A" to "F"
System.out.println(Hipster.createDijkstra(p).search("F"));

Il vous suffit de remplacer la définition du graphique par la vôtre, puis d'instancier l'algorithme comme dans l'exemple.

J'espère que ça aide!

5
Adrián González

C'est peut-être trop tard mais Personne n'a fourni d'explication claire sur le fonctionnement de l'algorithme

L'idée de Dijkstra est simple, permettez-moi de le montrer avec le pseudocode suivant.

Dijkstra partitionne tous les nœuds en deux ensembles distincts. Instable et réglé. Initialement, tous les nœuds sont dans l'ensemble non réglé, par exemple ils doivent encore être évalués.

Au début, seul le nœud source est placé dans l'ensemble des nœuds installés. Un nœud spécifique sera déplacé vers l'ensemble réglé si le chemin le plus court de la source à un nœud particulier a été trouvé.

L'algorithme s'exécute jusqu'à ce que l'ensemble unsettledNodes soit vide. Dans chaque itération, il sélectionne le nœud avec la distance la plus faible au nœud source dans l'ensemble unsettledNodes. Par exemple. Il lit tous les tronçons sortants de la source et évalue chaque nœud de destination à partir de ces tronçons qui ne sont pas encore réglés.

Si la distance connue de la source à ce nœud peut être réduite lorsque l'Edge sélectionné est utilisé, la distance est mise à jour et le nœud est ajouté aux nœuds qui nécessitent une évaluation.

Veuillez noter que Dijkstra détermine également le pré-successeur de chaque nœud sur son chemin vers la source. J'ai laissé cela hors du pseudo code pour le simplifier.

Crédits à Lars Vogel

3
user3829791

Conservez une liste de nœuds vers lesquels vous pouvez vous rendre, triée en fonction de la distance à partir de votre nœud de départ. Au début, seul votre nœud de départ sera dans la liste.

Bien que vous n'ayez pas atteint votre destination: visitez le nœud le plus proche du nœud de départ, ce sera le premier nœud de votre liste triée. Lorsque vous visitez un nœud, ajoutez tous ses nœuds voisins à votre liste, sauf ceux que vous avez déjà visités. Répéter!

1
Akinakes

Vous pouvez voir un exemple complet en utilisant Java 8, récursivité et flux -> algorithme Dijkstra avec Java

0
Jesus Dana