The problem is a binary maze where 1's are walls and 0's are valid paths. You start from the top left (0,0) and you have to reach the bottom right (width -1, height -1). You have to find the shortest path from the top left to the bottom right. The twist comes in because you are allowed to remove one wall at most and this is the part that is confusing me. My current code can solve the shortest path without calculating for a wall being removed.
Here are a couple of examples: [0,1,1,0], [0,0,0,1], [1,1,0,0], [1,1,1,0] Answer: 7 moves (including entrance and exit)
Example 2: [0,0,0,0,0],[0,1,1,1,0],[1,0,0,0,0],[0,1,1,1,1],[0,1,1,1,1],[0,0,0,0,0] Answer: 11 (Because you can break the wall at position [0][1] to make the path shorter)
So like I said before my code will find the shortest path, but at the moment doesn't try to remove a wall for a shorter path, mostly because I dont understand how to. I was thinking that I remove one wall at a time and continually re-run to see if a shorter path is produced but this seems very costly operation, but it might get the job done. However, I was hoping that I could find a more clear and easier way to do so.
import java.util.*;
public class Maze {
public static void main(String [] args)
{
int[][] arr = new int[][] {
{0,0,0,0,0},
{1,1,1,1,0},
{0,0,0,0,0},
{0,1,1,1,1},
{0,1,1,1,1},
{0,0,0,0,0},
};
answer(arr);
}
public static int answer(int[][] maze) {
maze[maze.length-1][maze[0].length -1] = 9;
Point p = getPathBFS(0,0,maze);
int length = 1;
while(p.getParent() != null) {
p = p.getParent();
length++;
}
System.out.println(length);
return length;
}
private static class Point {
int x;
int y;
Point parent;
public Point(int x, int y, Point parent) {
this.x = x;
this.y = y;
this.parent = parent;
}
public Point getParent() {
return this.parent;
}
}
public static Queue<Point> q = new LinkedList<Point>();
public static Point getPathBFS(int x, int y,int[][] arr) {
q.add(new Point(x,y, null));
while(!q.isEmpty()) {
Point p = q.remove();
if (arr[p.x][p.y] == 9) {
return p;
}
if(isFree(p.x+1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x+1,p.y, p);
q.add(nextP);
}
if(isFree(p.x-1,p.y,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x-1,p.y, p);
q.add(nextP);
}
if(isFree(p.x,p.y+1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y+1, p);
q.add(nextP);
}
if(isFree(p.x,p.y-1,arr)) {
arr[p.x][p.y] = -1;
Point nextP = new Point(p.x,p.y-1, p);
q.add(nextP);
}
}
return null;
}
public static boolean isFree(int x, int y,int[][] arr) {
if((x >= 0 && x < arr.length) && (y >= 0 && y < arr[x].length) && (arr[x][y] == 0 || arr[x][y] == 9)) {
return true;
}
return false;
}
}
You use a Point class to represent the position of the player as he walks through the maze. Without the wall rule, this position is all you need to know about the player to determine what he can do next, and so you can do BFS on the directed graph of all possible positions to find the path.
With the wall rule, in order to determine where the player can go next, you also have to know whether or not he has already removed a wall, so the full state of the player includes not only his position, but also a boolean that indicates whether or not a wall has been removed.
You can then do BFS on the graph of these expanded states to find the shortest path with at most one wall removed.
Since you've posted your actual code for the simpler problem, I'll just fix it up with the expanded state (and a Set to keep you from visiting the same state twice, instead of modifying arr):