简体   繁体   中英

Calculate the shortest path from start to end, if we have the ability to overcome at MOST 1 obstacle

We're given a Maze in the form of a 2D Matrix of integers; where 0's are passible space and 1's are walls.

The starting position will always be :

array[0][0]
and the end will always be :
 array[HEIGHT -1][WIDTH-1]  
The only possible moves are up, down, right, or left. I would like to find the shortest path from start to end, considering that we can overcome at most 1 wall inside of the maze. I started out by creating a Maze class and a Vertex Class. My first thought was to use BFS, however, I have recently realized that this of course will not work, and I am now trying Dijkstra's Algorithm. An idea is to give the Wall's weights that are greatly more expensive than the passible space and use Dijkstra's to find the shortest path from start to finish. Then, calculate each Wall's shortest path to the end. After this, I'm thinking that I can compare the paths of the Walls to the end, with the path of the start to the end, and somehow use this to decide if removing a wall will give me a shorter path.

I'm really struggling with Dijkstra and putting all of this together to perhaps get something useful. I started with creating a Maze class, that would take the 2d array input and make a graph out of it. Maze Class :

  class Maze{ Vertex[][] vertices; ArrayList<Edge> edges; ArrayList<Vertex> walls; HashSet<Vertex> settledVertices; HashSet<Vertex> unsettledVertices; HashMap<Vertex,Integer> distanceMap; HashMap<Vertex,Vertex> predecessors; Vertex start, end; int width; int height; //Maze Contructor public Maze(int arr[][]){ this.height = arr.length; this.width = arr[0].length; this.vertices = new Vertex[height][width]; this.edges = new ArrayList<>(); this.walls = new ArrayList<>(); for(int i = 0 ; i < height; i++){ for(int j = 0; j < width; j++){ this.vertices[i][j] = arr[i][j] == 1 ? new Wall(arr[i][j]) : new Vertex(arr[i][j]); if(this.vertices[i][j].value == 1) this.walls.add(this.vertices[i][j]); } } //Build() sets the Edges and their weights, as well as determine each Vertexs neighbors build(); this.start = this.vertices[0][0]; this.end = this.vertices[height-1][width-1]; } //Attempting Dijkstra public void executeDij(Vertex source){ this.settledVertices = new HashSet<>(); this.unsettledVertices = new HashSet<>(); this.distanceMap = new HashMap<>(); this.predecessors = new HashMap<>(); this.distanceMap.put(source,0); this.unsettledVertices.add(source); while(unsettledVertices.size() > 0){ Vertex v = getMinimum(unsettledVertices); unsettledVertices.remove(v); findMinDistance(v); } } public int getDistance(Vertex arrow, Vertex target){ for(Edge e : edges) if(e.source.equals(arrow) && e.destination.equals(target)) return e.weight; throw new RuntimeException("Get distance error"); } public void findMinDistance(Vertex vertex){ for (Vertex target : vertex.neighbors) { if(getShortestDistance(target) > getShortestDistance(vertex) + getDistance(vertex, target)) distanceMap.put(target, getShortestDistance(vertex) + getDistance(vertex,target)); } } public int getShortestDistance(Vertex destination){ Integer d = distanceMap.get(destination); if(d == null) return Integer.MAX_VALUE; return d; } public Vertex getMinimum(HashSet<Vertex> set){ Vertex min = null; for(Vertex v : set){ if(min == null){ min = v; }else{ if(getShortestDistance(v) < getShortestDistance(min)){ min = v; } } } return min; } public boolean isSettled(Vertex v){ return settledVertices.contains(v); } public LinkedList<Vertex> getPath(Vertex target){ LinkedList<Vertex> path = new LinkedList<>(); Vertex singleStep = target; if(predecessors.get(singleStep) == null) return null; path.add(singleStep); while(predecessors.get(singleStep) != null){ singleStep = predecessors.get(singleStep); path.add(singleStep); } Collections.reverse(path); return path; } 

My Vertex Class :

  class Vertex{ int value; boolean visited; int distance; Vertex previous; ArrayList<Vertex> neighbors = new ArrayList<>(); public Vertex(int value){ this.value = value; } public boolean isWall(){ return this.value == 1; } public void setVisited(){ this.visited = true; } public int getValue(){ return this.value; } } 

I've basically lost myself at this point and I'm not sure what I'm even doing anymore. When I try to use my getPath method, I get an Null Pointer Exception. In all, I guess my question is how can I get the least expensive path from Start to End, and then the path of the Walls to the end; for each Wall.

Using Dijkstra's Algorithm to build shortest path to any point is good, but do it both from Start and from End.

Let's say you have this maze, using _ for Space and X for Wall:

s  _  _  X  _  _ 
X  _  X  X  _  X 
_  _  X  _  _  _ 
_  X  _  _  X  _ 
_  X  X  _  X  _ 
_  _  X  _  _  e 

First, fill in shortest distance from Start:

s  s1 s2 X  _  _ 
X  s2 X  X  _  X 
s4 s3 X  _  _  _ 
s5 X  _  _  X  _ 
s6 X  X  _  X  _ 
s7 s8 X  _  _  _ 

If that got you to the end, you're done without having to jump a wall.
Otherwise, fill in shortest distance from End:

s  s1 s2 X  e6 e7
X  s2 X  X  e5 X 
s4 s3 X  e5 e4 e3
s5 X  e5 e4  X e2
s6 X  X  e3  X e1
s7 s8 X  e2 e1 e 

Now, find walls that are next to a start value and an end value:

s  s1 s2 -- e6 e7
X  s2 X  X  e5 X 
s4 s3 -- e5 e4 e3
s5 -- e5 e4  X e2
s6 X  X  e3  X e1
s7 s8 -- e2 e1 e 

Choose a wall with the smallest sum of the two distances.
Of the 4 candidates, 3 have sum 8, and 1 has sum 10.
There are here a total of 5 solutions:

s →s1→s2→--→e6 e7 │ s →s1 s2 -- e6 e7 │ s →s1 s2 -- e6 e7 │ s →s1 s2 -- e6 e7 │ s →s1 s2 -- e6 e7
            ↓↓    │    ↓↓             │    ↓↓             │    ↓↓             │    ↓↓            
X  s2 X  X  e5 X  │ X  s2 X  X  e5 X  │ X  s2 X  X  e5 X  │ X  s2 X  X  e5 X  │ X  s2 X  X  e5 X 
            ↓↓    │    ↓↓             │    ↓↓             │    ↓↓             │    ↓↓            
s4 s3 -- e5 e4→e3 │ s4 s3→--→e5→e4→e3 │ s4 s3→--→e5 e4 e3 │ s4 s3→-- e5 e4 e3 │ s4 s3 -- e5 e4 e3
               ↓↓ │                ↓↓ │          ↓↓       │       ↓↓          │    ↓↓          
s5 -- e5 e4  X e2 │ s5 -- e5 e4  X e2 │ s5 -- e5 e4  X e2 │ s5 -- e5→e4  X e2 │ s5 --→e5→e4  X e2
               ↓↓ │                ↓↓ │          ↓↓       │          ↓↓       │          ↓↓      
s6 X  X  e3  X e1 │ s6 X  X  e3  X e1 │ s6 X  X  e3  X e1 │ s6 X  X  e3  X e1 │ s6 X  X  e3  X e1
               ↓↓ │                ↓↓ │          ↓↓       │          ↓↓       │          ↓↓      
s7 s8 -- e2 e1 e  │ s7 s8 -- e2 e1 e  │ s7 s8 -- e2→e1→e  │ s7 s8 -- e2→e1→e  │ s7 s8 -- e2→e1→e 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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