繁体   English   中英

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

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

我在这里看过其他有关此事的帖子。

我试图找到图中节点之间的最短路径。 节点之间的每个边具有(X, Y)坐标。

我想计算从Node INode J的最短距离。 一旦有了,我想从最短路径的坐标中加起所有X值和Y值。

我已经坚持了好几个小时,并且喜欢一些见解。

这是代码:

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

如果我从这个文本文件中读取

3 //坐标数

0 0 //(x,y)

1 1 //(x,y)

2 0 //(x,y)

1 2 //坐标1到2之间的边缘

2 3 //坐标2到3之间的边缘

我的测试用例看起来像这样:

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

要解决此问题,您需要跟踪每个节点,Dijktra树中该节点的父节点是什么。 一旦你跟踪了你能够以递归方式恢复最短路径,就可以遍历它并计算你需要知道的内容。

你的问题在这部分:

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

每次运行时间shortestPath方法,你应该重置所有minDistance在所有的顶点到无穷大,不只是startVertex

对于除startVertex之外的所有顶点,开头的minDistance应设置为无穷大(或Double.MAX_VALUE ),或者始终为0

码:

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

此外,在Test类的第三个循环中,您初始化多个相同的顶点。 所以,你应该做的是,预先初始化所有顶点并将它们保存在这样的数组中:

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


}

正如所承诺的那样,我为我的二分图解算器创建了一个github repo。 你可以看一下: GitHub上的Bipartite Solver

正如您所解释的那样,您有一组点,您正试图找到它们之间的最小距离。 你有一大堆X和Y坐标,并且你试图找到节点之间最小的欧氏距离。

您最感兴趣的算法是Jonker-Volgenant,它实现了Dijkstra的遍历节点的算法。

该库包含一组可以运行以测试代码的独立可执行文件

如果这对您有用,请告诉我。

暂无
暂无

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

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