带有诡计的二元迷宫

时间:2017-04-29 22:12:18

标签: java breadth-first-search maze

问题是二元迷宫,其中1是墙,0是有效路径。从左上角(0,0)开始,你必须到达右下角(宽度-1,高度-1)。你必须找到从左上角到右下角的最短路径。扭曲是因为你被允许最多移除一面墙,这是令我困惑的部分。我当前的代码可以解决最短路径而无需计算被移除的墙。

以下是几个例子: [0,1,1,0],[0,0,0,1],[1,1,0,0],[1,1,1,0]答案:7次移动(包括入口和出口)< / p>

示例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]答案:11(因为你可以在位置[0] [1]打破墙壁以缩短路径)

就像我之前说的那样,我的代码会找到最短的路径,但此刻并没有尝试移除一条较短路径的墙,主要是因为我不明白该怎么做。我想我一次拆除一面墙并不断重新运行以查看是否产生了更短的路径,但这似乎是非常昂贵的操作,但它可能会完成工作。但是,我希望我能找到一种更清晰,更简单的方法。

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

2 个答案:

答案 0 :(得分:1)

要注意的事实是,通过迷宫移除一个部分的最短路径包括两条最短路径 - 从入口到移除部分,然后从移除部分到退出。

您可以使用BFS计算迷宫中所有位置与起始位置的距离以及所有位置距离结束位置的距离。

然后你可以找到一个位置,入口和出口的距离总和是最小的。如果它是墙壁部分,则它是要移除的部分。否则,删除任何部分都没有用。

总体而言,此解决方案以线性时间运行。

答案 1 :(得分:0)

你使用Point类来表示玩家走过迷宫时的位置。如果没有墙壁规则,这个位置就是玩家需要知道的,以确定他接下来可以做什么,所以你可以在所有可能位置的有向图上做BFS来找到路径。

根据墙壁规则,为了确定玩家下一步的位置,您还必须知道他是否已经移除了墙壁,因此玩家的完整状态不仅包括他的位置,还包括布尔值,表示墙是否已被移除。

然后,您可以在这些展开状态的图形上执行BFS,以找到最多只删除一个墙的最短路径。

由于您已针对更简单的问题发布了实际代码,因此我只是将其与扩展状态进行修复(并设置为阻止您访问同一状态两次,而不是修改arr) :

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;
            State 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 State {
            int x;
            int y;
            boolean wallRemoved;

            State parent;

            public State(int x, int y, boolean wallRemoved, State parent) {
                this.x = x;
                this.y = y;
                this.wallRemoved = wallRemoved;
                this.parent = parent;
            }

            public State getParent() {
                return this.parent;
            }

            @Override
            public int hashCode() {
                final int prime = 31;
                int result = 1;
                result = prime * result + (wallRemoved ? 1231 : 1237);
                result = prime * result + x;
                result = prime * result + y;
                return result;
            }

            @Override
            public boolean equals(Object obj)  {
                if (this == obj)
                    return true;
                if (obj == null ||getClass() != obj.getClass())
                    return false;
                State other = (State) obj;
                if (wallRemoved != other.wallRemoved)
                    return false;
                if (x != other.x)
                    return false;
                if (y != other.y)
                    return false;
                return true;
            }

      }
      public static Queue<State> q = new LinkedList<>();
      public static HashSet<State> seen = new HashSet<>();

        public static State getPathBFS(int x, int y,int[][] arr) {

            q.add(new State(x,y,false, null));

            while(!q.isEmpty()) {
                State p = q.remove();

                if (arr[p.x][p.y] == 9) {
                    return p;
                }

                tryNext(p,p.x+1,p.y,arr);
                tryNext(p,p.x-1,p.y,arr);
                tryNext(p,p.x,p.y+1,arr);
                tryNext(p,p.x,p.y-1,arr);
            }
            return null;
        }

        public static void tryNext(State p, int x, int y, int[][]arr)  {
            if (x<0 || y<0 || x>=arr.length || y>=arr[x].length)
                return;
            State newState;
            if (arr[x][y] == 0 || arr[x][y]==9)  {
                newState = new State(x, y, p.wallRemoved, p);
            } else if (!p.wallRemoved) {
                newState = new State(x, y, true, p);
            } else {
                return;
            }
            if (seen.add(newState)) {
                q.add(newState);
            }
        }
    }