数据结构java迷宫寻路

给定一个M行N列的迷宫图,其中 "0"表示可通路,"1"表示障碍物,无法通行。在迷宫中只允许在水平或上下四个方向的通路上行走,走过的位置不能重复走。

5行8列的迷宫如下:

0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 0 0 0 0 0 0 0
则从左上角(1,1)至右下角(5,8)的最短路径为:

1,1--》2,1--》2,2--》2,3--》3,3--》3,4--》3,5--》4,5--》5,5--》5,6--》5,7--》5,8

题目保证每个迷宫最多只有一条最短路径。

请输出该条最短路径,如果不存在任何通路,则输出"NO FOUND".

输入格式:
第一行,输入M和N值,表示迷宫行数和列数。

接着输入M行数值,其中,0表示通路,1表示障碍物。每列数值用空格符间隔。

接下来可能输入多组迷宫数据。

当输入M的值为-1时结束输入。

输出格式:
按行顺序输出路径的每个位置的行数和列数,如 x,y

如果不存在任何路径,则输出"NO FOUND".

每组迷宫寻路结果用换行符间隔。

输入样例:
在这里给出一组迷宫。例如:

8 8
0 0 1 0 0 0 1 0
0 0 1 0 0 0 1 0
0 0 0 0 1 1 0 0
0 1 1 1 0 0 0 0
0 0 0 1 0 0 0 0
0 1 0 0 0 1 0 0
0 1 1 1 0 1 1 0
1 0 0 0 0 0 0 0
4 4
0 0 1 0
0 0 0 0
0 0 1 1
0 1 0 0
-1 -1
输出样例:
在这里给出相应的输出。例如:

1,1
2,1
3,1
4,1
5,1
5,2
5,3
6,3
6,4
6,5
7,5
8,5
8,6
8,7
8,8

想起之前看过一个A*寻路算法,来自:《漫画算法 - 小灰的算法之旅》,不纠结复杂度的话,可以直接用dfs四向查找。

//迷宫地图
public static final int[][] MAZE = {
    { 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 1, 0, 0, 0 },
    { 0, 0, 0, 1, 0, 0, 0 },
    { 0, 0, 0, 1, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0 }
};

/**
 * A*寻路主逻辑
 * @param start 迷宫起点
 * @param end 迷宫终点
 */
public static Grid aStarSearch(Grid start, Grid end) {
    ArrayList<Grid> openList = new ArrayList<Grid>();
    ArrayList<Grid> closeList = new ArrayList<Grid>();
    //把起点加入 openList
    openList.add(start);
    //主循环,每一轮检查1个当前方格节点
    while (openList.size() > 0) {
        // 在openList中查找 F值最小的节点,将其作为当前方格节点
        Grid currentGrid = findMinGird(openList);
        // 将当前方格节点从openList中移除
        openList.remove(currentGrid);
        // 当前方格节点进入 closeList
        closeList.add(currentGrid);
        // 找到所有邻近节点
        List<Grid> neighbors = findNeighbors(currentGrid, openList, closeList);
        for (Grid grid : neighbors) {
            if (!openList.contains(grid)) {
                //邻近节点不在openList中,标记“父节点”、G、H、F,并放入openList
                grid.initGrid(currentGrid, end);
                openList.add(grid);
            }
        }
        //如果终点在openList中,直接返回终点格子
        for (Grid grid : openList){
            if ((grid.x == end.x) && (grid.y == end.y)) {
                return grid;
            }
        }
    }
//openList用尽,仍然找不到终点,说明终点不可到达,返回空
return null;
}

private static Grid findMinGird(ArrayList<Grid> openList) {
    Grid tempGrid = openList.get(0);
    for (Grid grid : openList) {
        if (grid.f < tempGrid.f) {
            tempGrid = grid;
        }
    }
    return tempGrid;
}

private static ArrayList<Grid> findNeighbors(Grid grid, List<Grid> openList, List<Grid> closeList) {
    ArrayList<Grid> gridList = new ArrayList<Grid>();
    if (isValidGrid(grid.x, grid.y-1, openList, closeList)) {
        gridList.add(new Grid(grid.x, grid.y - 1));
    }
    if (isValidGrid(grid.x, grid.y+1, openList, closeList)) {
        gridList.add(new Grid(grid.x, grid.y + 1));
    }
    if (isValidGrid(grid.x-1, grid.y, openList, closeList)) {
        gridList.add(new Grid(grid.x - 1, grid.y));
    }
    if (isValidGrid(grid.x+1, grid.y, openList, closeList)) {
        gridList.add(new Grid(grid.x + 1, grid.y));
    }
    return gridList;
}

private static boolean isValidGrid(int x, int y, List<Grid> openList, List<Grid> closeList) {
    //是否超过边界
    if (x < 0 || x >= MAZE.length || y < 0 || y >= MAZE[0].length) {
        return false;
    }
    //是否有障碍物
    if(MAZE[x][y] == 1){
        return false;
    }
    //是否已经在openList中
    if(containGrid(openList, x, y)){
        return false;
    }
    //是否已经在closeList中
    if(containGrid(closeList, x, y)){
        return false;
    }
    return true;
}

private static boolean containGrid(List<Grid> grids, int x, int y) {
    for (Grid grid : grids) {
        if ((grid.x == x) && (grid.y == y)) {
            return true;
        }
    }
    return false;
}

tatic class Grid {
    public int x;
    public int y;
    public int f;
    public int g;
    public int h;
    public Grid parent;

    public Grid(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void initGrid(Grid parent, Grid end){
        this.parent = parent;
        if(parent != null){
            this.g = parent.g + 1;
        } else {
            this.g = 1;
        }
        this.h = Math.abs(this.x - end.x) + Math.abs(this.y - end.y);
        this.f = this.g + this.h;
    }
}

public static void main(String[] args) {
    //设置起点和终点
    Grid startGrid = new Grid(2, 1);
    Grid endGrid = new Grid(2, 5);
    //搜索迷宫终点
    Grid resultGrid = aStarSearch(startGrid, endGrid);
    //回溯迷宫路径
    ArrayList<Grid> path = new ArrayList<Grid>();
    while (resultGrid != null) {
        path.add(new Grid(resultGrid.x, resultGrid.y));
        resultGrid = resultGrid.parent;
    }
    //输出迷宫和路径,路径用*表示
    for (int i = 0; i < MAZE.length; i++) {
        for (int j = 0; j < MAZE[0].length; j++) {
            if (containGrid(path, i, j)) {
                System.out.print("*, ");
            } else {
                System.out.print(MAZE[i][j] + ", ");
                }
            }
        System.out.println();
    }
}

作者:小灰
链接:https://leetcode-cn.com/leetbook/read/journey-of-algorithm/52thz6/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。