[英]ArrayIndexOutOfBoundsException in Dijkstra's shortest path algorithm
[英]Use Dijkstra's algorithm to get shortest path when distance are as coordinates
我在這里看過其他有關此事的帖子。
我試圖找到圖中節點之間的最短路徑。 節點之間的每個邊具有(X, Y)
坐標。
我想計算從Node I
到Node 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.