Java-найти кратчайший путь между 2 точками на взвешенной карте расстояния

Мне нужен алгоритм для поиска кратчайшего пути между двумя точками на карте где расстояние между дорогами обозначается номером.

то, что дано: Начало Городу Город Назначения Z

список расстояний между городами:

A-B : 10
F-K : 23
Р - М : 8
К - О : 40
Z-P : 18
J-K : 25
Д - Б : 11
М - А : 8
Р - Р : 15

Я думал, что могу использовать алгоритм Дейкстры, однако он находит кратчайшее расстояние до всех пунктов назначения. не один.

любое предложение приветствуется.

4 ответов


как SplinterReality сказал:There's no reason not to use Dijkstra's algorithm here.

код ниже, который я взял из здесь и изменил его, чтобы решить пример в вопрос.

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);
    }
}

код выше производит:

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

по оценкам sanjan:

идея алгоритма Дейкстры заключается в том, чтобы исследовать все узлы графа упорядоченным образом. Алгоритм хранит приоритетную очередь, где узлы упорядочены по стоимости с самого начала, и на каждой итерации алгоритма выполняются следующие операции:

  1. извлеките из очереди узел с наименьшей стоимостью с самого начала, N
  2. получить своих соседей (N') и связанные с ними расходы, которые стоимость (N) + стоимость(N, N')
  3. вставьте в очередь соседние узлы N', с приоритетом, заданным их стоимостью

верно, что алгоритм вычисляет стоимость пути между началом (в вашем случае A) и всеми остальными узлами, но вы можете остановить исследование алгоритма, когда он достигнет цели (Z в вашем примере). На данный момент Вы знаете стоимость между A и Z, и путь, соединяющий их.

Я рекомендую вам использовать библиотеку который реализует этот алгоритм вместо того, чтобы кодировать свой собственный. В Java вы можете взглянуть на хипстер библиотека, который имеет очень удобный способ создать график и начать использовать алгоритмы поиска.

здесь у вас есть пример того, как определить график и начать использовать Dijstra с 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"));

вам нужно только заменить определение графика своим собственным, а затем создать экземпляр алгоритма, как в образец.

надеюсь, это поможет!


Это может быть слишком поздно, но никто не дал четкого объяснения того, как работает алгоритм

идея Dijkstra проста, позвольте мне показать это со следующим псевдокодом.

Dijkstra разбивает все узлы на два разных набора. Устоялись и осели. Первоначально все узлы находятся в неурегулированном наборе, например, они должны быть все еще оценены.

сначала в набор settledNodes помещается только исходный узел. Конкретного узла к установленному набору, если найден кратчайший путь от источника к определенному узлу.

алгоритм работает до тех пор, пока набор unsettledNodes не будет пустым. На каждой итерации он выбирает узел с наименьшим расстоянием до исходного узла из набора unsettledNodes. Например. Он считывает все ребра, исходящие из источника, и оценивает каждый узел назначения из этих ребер, которые еще не установлены.

Если известное расстояние от источника до этого узла может быть уменьшается при использовании выбранного ребра, расстояние обновляется и узел добавляется к узлам, которые нуждаются в оценке.

обратите внимание, что Dijkstra также определяет предварительный преемник каждого узла на пути к источнику. Я оставил это из псевдокода, чтобы упростить его.

кредиты Ларс Вогель


ведение списка узлов, в которые вы можете путешествовать, отсортированных по расстоянию от начального узла. Вначале в списке будет только ваш начальный узел.

пока вы не достигли места назначения: посетите узел, ближайший к стартовому узлу, это будет первый узел в вашем отсортированном списке. При посещении узла добавьте в список все соседние узлы, кроме уже посещенных. Повторяю!