简体   繁体   English

当距离为坐标时,使用Dijkstra算法获得最短路径

[英]Use Dijkstra's algorithm to get shortest path when distance are as coordinates

I had a looked at other posts regarding this here at SO. 我在这里看过其他有关此事的帖子。

I'm trying to find the shortest path between nodes in a graph. 我试图找到图中节点之间的最短路径。 Each edge between nodes has an (X, Y) coordinate. 节点之间的每个边具有(X, Y)坐标。

I want to calculate the shortest distance from Node I to Node J . 我想计算从Node INode J的最短距离。 Once have that I want to add up all the X values and Y values from the coordinates in shortest path. 一旦有了,我想从最短路径的坐标中加起所有X值和Y值。

I have been stuck at this for hours and would love some insight. 我已经坚持了好几个小时,并且喜欢一些见解。

Here is the code: 这是代码:

class Vertex implements Comparable<Vertex> {
    private int id;
    private List<Edge> adjacencyList;
    private Vertex previousVertex;
    private double minDistance;
    private Coordinate point;

    public Vertex(int id, Coordinate point) {
        this.id = id;
        this.point = point;
        this.adjacencyList = new ArrayList<>();
    }

    public int getID() {
        return this.id;
    }

    public Coordinate getPoint() {
        return this.point;
    }

    public List<Edge> getAdjacencyList() {
        return this.adjacencyList;
    }

    public void addNeighbour(Edge edge) {
        this.adjacencyList.add(edge);
    }

    public Vertex getPreviousVertex() {
        return this.previousVertex;
    }

    public void setPreviousVertex(Vertex previousVertex) {
        this.previousVertex = previousVertex;
    }

    public double getMinDistance() {
        return this.minDistance;
    }

    public void setMinDistance(double minDistance) {
        this.minDistance = minDistance;
    }

    public int compareTo(Vertex other) {
        return Double.compare(this.minDistance, other.minDistance);
    }
}


class Edge {
    private double weight;
    private Vertex targetVertex;

    public Edge(double weight, Vertex targetVertex) {
        this.weight = weight;
        this.targetVertex = targetVertex;
    }

    public double getWeight() {
        return this.weight;
    }

    public void setWeight(double weight) {
        this.weight = weight;
    }

    public Vertex getTargetVertex() {
        return this.targetVertex;
    }

    public void setTargetVertex(Vertex targetVertex) {
        this.targetVertex = targetVertex;
    }
}

class Algorithm {
    public void shortestPath(Vertex startVertex) {
        startVertex.setMinDistance(0);
        PriorityQueue<Vertex> queue = new PriorityQueue<>();
        queue.add(startVertex);

        while (!queue.isEmpty()) {
            Vertex actualVertex = queue.poll();

            for (Edge edge : actualVertex.getAdjacencyList()) {
                Vertex v = edge.getTargetVertex();
                double weight = edge.getWeight();               
                double currentDistance = actualVertex.getMinDistance() + weight;

                if (currentDistance < v.getMinDistance()) {
                    queue.remove(v);
                    v.setMinDistance(currentDistance);
                    v.setPreviousVertex(actualVertex);
                    queue.add(v);
                }
            }
        }
    }

    public List<Vertex> getShortestPathTo(Vertex targetVertex){
        List<Vertex> path = new ArrayList<Vertex>();
        for (Vertex vertex = targetVertex; vertex != null; vertex = vertex.getPreviousVertex()){
            path.add(vertex);
        }
        Collections.reverse(path);
        return path;    
    }
}

class Coordinate {
    private int x;
    private int y;

    Coordinate(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return this.x;
    } 

    public int getY() {
        return this.y;
    }

    public static Coordinate readInput(Scanner in) {
       String[] temp = in.nextLine().split(" ");
       return new Coordinate(Integer.parseInt(temp[0]), Integer.parseInt(temp[1]));
    }
}

If I read from this textfile 如果我从这个文本文件中读取

3 //# of coordinates 3 //坐标数

0 0 // (x, y) 0 0 //(x,y)

1 1 // (x, y) 1 1 //(x,y)

2 0 // (x, y) 2 0 //(x,y)

1 2 //edge between coordinate 1 to 2 1 2 //坐标1到2之间的边缘

2 3 //edge between coordinate 2 to 3 2 3 //坐标2到3之间的边缘

My test case would look like this: 我的测试用例看起来像这样:

class Test {
    public static void main(String[] args) {

        Scanner s = new Scanner(System.in);
        String[] constants = s.nextLine().split(" ");

        final int N = Integer.parseInt(constants[0]);

        List<Coordinate> junctions = new ArrayList<>();
        List<Coordinate> paths = new ArrayList<>();
        List<Vertex> vertices = new ArrayList<>();

        for(int i = 0; i < N; i++) {
            junctions.add(Coordinate.readInput(s));
        }

        for(int i = 0; i < N-1; i++) {
            paths.add(Coordinate.readInput(s));
        }

        for(int i = 0; i < N-1; i++) {
            int x = junctions.get(paths.get(i).getX() - 1).getX();
            int x1 = junctions.get(paths.get(i).getY() - 1).getX();
            int y = junctions.get(paths.get(i).getX() - 1).getY();
            int y1 = junctions.get(paths.get(i).getY() - 1).getY();

            Vertex vertex1 = new Vertex(paths.get(i).getX(), new Coordinate(x, y));
            Vertex vertex2 = new Vertex(paths.get(i).getY(), new Coordinate(x1, y1));

            double distance = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2));

            vertex1.addNeighbour(new Edge(distance, vertex2));

            vertices.add(vertex1);
            vertices.add(vertex2);
        }

        Algorithm a = new Algorithm();
        int x = 0;
        int y = 0;

        for(int i = 0; i < vertices.size(); i++) {
            a.shortestPath(vertices.get(i));

            for(Vertex vertex : a.getShortestPathTo(vertices.get(i+1))) {
                x += vertices.get(vertex.getID()).getPoint().getX();
                y += vertices.get(vertex.getID()).getPoint().getY();
            }

        }
        //This prints out "Total X: 5 Total Y: 3" (should be 3 and 1)
        System.out.println("Total X: " + x + " Total Y: " + y);
    }
}

To solve this problem you need to keep track for each node, what is the parent of that node in the Dijktra's tree. 要解决此问题,您需要跟踪每个节点,Dijktra树中该节点的父节点是什么。 Once you keep track of that you are able to recover the shortest path recursively, traverse it and calculate what you need to know. 一旦你跟踪了你能够以递归方式恢复最短路径,就可以遍历它并计算你需要知道的内容。

Your problem is in this part: 你的问题在这部分:

public void shortestPath(Vertex startVertex) {
    startVertex.setMinDistance(0);
    PriorityQueue<Vertex> queue = new PriorityQueue<>();
    queue.add(startVertex);
    //The rest is omitted
}

Each time you run the shortestPath method, you should reset all the minDistance in all vertexes to infinity, not just the startVertex . 每次运行时间shortestPath方法,你应该重置所有minDistance在所有的顶点到无穷大,不只是startVertex

For all vertexes except the startVertex , the minDistance at the beginning should be set to infinity (or Double.MAX_VALUE ) , or it will always be 0 . 对于除startVertex之外的所有顶点,开头的minDistance应设置为无穷大(或Double.MAX_VALUE ),或者始终为0

Code: 码:

for(Vertex v : vertices){
    v.setMinDistance(Double.MAX_VALUE);
    v.setPreviousVertex(null);  
}
a.shortestPath(vertices.get(i));

Further more, in your third loop of the class Test , you initialize same vertex more than one. 此外,在Test类的第三个循环中,您初始化多个相同的顶点。 So, what you should do is, pre-initializing all the vertexes and keep them in an array like this: 所以,你应该做的是,预先初始化所有顶点并将它们保存在这样的数组中:

for(int i = 0; i < N; i++){
    vertices.add(new Vertex(i + 1, junctions.get(i)); 
}

for(int i = 0; i < N - 1; i++){
    //Initialize x, y, x1, y1 here, I just skipped it
    Vertex vertex1 = vertices.get(paths.getX() - 1);
    Vertex vertex2 = vertices.get(paths.getY() - 1);

    double distance = Math.sqrt(Math.pow(x - x1, 2) + Math.pow(y - y1, 2));

    vertex1.addNeighbour(new Edge(distance, vertex2));


}

As promised, I have created a github repo for my bipartite graph solver. 正如所承诺的那样,我为我的二分图解算器创建了一个github repo。 You can take a look here: Bipartite Solver on GitHub 你可以看一下: GitHub上的Bipartite Solver

As you explained, you have a set of points you are trying to find the minimum distance between. 正如您所解释的那样,您有一组点,您正试图找到它们之间的最小距离。 You have a whole bunch of X and Y coordinates, and you are attempting to find the smallest total euclidean distance between nodes. 你有一大堆X和Y坐标,并且你试图找到节点之间最小的欧氏距离。

The algorithm you are most interested in is Jonker-Volgenant, which implements Dijkstra's Algorithm for traversing nodes. 您最感兴趣的算法是Jonker-Volgenant,它实现了Dijkstra的遍历节点的算法。

The library includes a bunch of standalone executables you can run to test the code. 该库包含一组可以运行以测试代码的独立可执行文件

Let me know if this is useful to you. 如果这对您有用,请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM