【问题标题】:How can I make this more efficient path finding?我怎样才能使这种更有效的路径查找?
【发布时间】:2017-06-16 20:59:14
【问题描述】:

我正在研究迷宫求解器。它在我的前两个迷宫中运行得非常快,但是,我的第三个迷宫需要永远。在合理的硬件上,我应该能够在一分钟内完成它。

解决方法在我的高端游戏设备上花费了大量时间。

这里是相关源码

import java.awt.Point;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;


/**
 * Created by jphamlett on 6/16/17.
 */
public class main {
    static class fileIO {

        public static String readFile(String path, Charset encoding)
                throws IOException {
            byte[] encoded = Files.readAllBytes(Paths.get(path));
            return new String(encoded, encoding);
        }
    }

    static class mazeNode {
        private Point point;
        private int dist;

        public Point getPoint() {
            return point;
        }

        public void setPoint(Point point) {
            this.point = point;
        }

        public int getDist() {
            return dist;
        }

        public void setDist(int dist) {
            this.dist = dist;
        }

        public mazeNode(Point point, int dist) {
            setPoint(point);
            setDist(dist);
        }

    }

    static class Solver {
        private String[] pathGrid;
        private int[][] gridLength;


        public void setPath(String path) {
            try {
                this.pathGrid = generatePath(fileIO.readFile(path, Charset.defaultCharset()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public Point findA() {
            for (int row = 0; row < pathGrid.length; row++) {
                int pos = pathGrid[row].indexOf("A");
                if (pos != -1) {
                    return new Point(row, pos);
                }
            }
            return null; // Something went wrong
        }

        public Point findB() {
            for (int row = 0; row < pathGrid.length; row++) {
                int pos = pathGrid[row].indexOf("B");
                if (pos != -1) {
                    return new Point(row, pos);
                }
            }
            return null; // Something went wrong
        }

        public Boolean canMove(char symbol) {
            return symbol != '#';
        }

        public String[] generatePath(String path) {
            return path.split("\n");
        }

        public String[] getPath() {
            return this.pathGrid;
        }

        // Use BFS to solve the maze
        public int[][] solve(int[][] gridLength, Point src, Point dest) {
            if (src == null || dest == null) {
                return null;
            }
            gridLength[src.x][src.y] = 0; // Distance to self is 0
            Boolean visited[][] = new Boolean[gridLength.length][gridLength[0].length]; //Set all booleans to false
            for (Boolean[] booleans : visited) {
                Arrays.fill(booleans, Boolean.FALSE);
            }
            //System.out.println("Finished making visited array");
            visited[src.x][src.y] = Boolean.TRUE;
            Queue<mazeNode> queue = new LinkedList<>();
            mazeNode initialNode = new mazeNode(src, 0);
            queue.add(initialNode);
            while (!queue.isEmpty()) {
                mazeNode currentNode = queue.peek();
                Point currentPoint = currentNode.getPoint();
                //System.out.println("Point: " + currentPoint);
                visited[currentPoint.x][currentPoint.y] = Boolean.TRUE;
                if (currentPoint.equals(dest)) {
                    return gridLength;
                }
                queue.poll();
                // Add adjacent valid cells
                try {
                    if (canMove(pathGrid[currentPoint.x].charAt(currentPoint.y - 1)) && !visited[currentPoint.x][currentPoint.y - 1]) {
                        gridLength[currentPoint.x][currentPoint.y - 1] = currentNode.getDist() + 1;
                        queue.add(new mazeNode(new Point(currentPoint.x, currentPoint.y - 1), currentNode.getDist() + 1));
                    }
                } catch (IndexOutOfBoundsException e) {

                }

                try {
                    if (canMove(pathGrid[currentPoint.x].charAt(currentPoint.y + 1)) && !visited[currentPoint.x][currentPoint.y + 1]) {
                        gridLength[currentPoint.x][currentPoint.y + 1] = currentNode.getDist() + 1;
                        queue.add(new mazeNode(new Point(currentPoint.x, currentPoint.y + 1), currentNode.getDist() + 1));
                    }
                } catch (IndexOutOfBoundsException e) {
                }
                try {
                    if (canMove(pathGrid[currentPoint.x - 1].charAt(currentPoint.y)) && !visited[currentPoint.x - 1][currentPoint.y]) {
                        gridLength[currentPoint.x - 1][currentPoint.y] = currentNode.getDist() + 1;
                        queue.add(new mazeNode(new Point(currentPoint.x - 1, currentPoint.y), currentNode.getDist() + 1));
                    }
                } catch (IndexOutOfBoundsException e) {
                }
                try {
                    if (canMove(pathGrid[currentPoint.x + 1].charAt(currentPoint.y)) && !visited[currentPoint.x + 1][currentPoint.y]) {
                        gridLength[currentPoint.x + 1][currentPoint.y] = currentNode.getDist() + 1;
                        queue.add(new mazeNode(new Point(currentPoint.x + 1, currentPoint.y), currentNode.getDist() + 1));
                    }
                } catch (IndexOutOfBoundsException e) {
                }
            }
            return null; // Cannot be reached
        }

        public Solver(String path) {
            setPath(path);
        }


    }


    public static void main(String[] args) {
        long startTime = System.currentTimeMillis();
        Solver solver = new Solver("mazes/maze3.txt");
        int[][] path = solver.solve(new int[solver.getPath().length][solver.getPath()[0].length()], solver.findA(), solver.findB());
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println(totalTime);
        for (int[] i : path) {
            for (int j : i) {
                System.out.print(j + " ");
            }
            System.out.println();
        }
        endTime = System.currentTimeMillis();
        totalTime = endTime - startTime;
        System.out.println(totalTime);

    }

}

这里是 maze2.txt

###############B#############################################
##.....########.#......................................#...##
##.###.#........####################################.#.#.#.##
##.###.#.#########..........#########.......########.#.#.#.##
##.#####...........########.#.......#.#####.########.#.#.#.##
##.########################.#.#####.#.#...#.########.#.#.#.##
##............................#####.#.##.##.########.#.#.#.##
##.###.############################.#.##.##.########.#.#.#.##
##.###.##...#...#...#...#...#.......#.##.##.########.#.#.#.##
##.###....#...#...#...#...#...#######.##.##.########.#.#.#.##
##.##################################.##.##.########.#.#.#.##
##.......................................##.########.#.#.#.##
###########################################.########.#.#.#.##
###...............................#########..........#.#.#.##
########################.###########################.#.#.#.##
#........................#...........................#.#.#.##
#.######################.#############################.#.#.##
#.#..........#.........................................#.#.##
#.#.########.#.#########################################.#.##
#.#........#.#.#.........................................#.##
#.##########.#.#.#########################################.##
#............#.#.##........................................##
##############.#.#############################.#####.########
#..............................................#####........#
########################A####################################

我附上了 maze3,因为这里的格式使它奇怪地移动。

https://pastebin.com/c4LhG5hT

【问题讨论】:

  • 我投票结束这个问题,因为它属于codereview.stackexchange.com
  • 也许你应该阅读Programming theory: Solve a maze。或者也许你应该调试你的代码,例如通过取消注释 currentPoint 的打印,您可以看到发生了什么。
  • 您应该使用带有曼哈顿距离启发式的 A* 搜索。
  • Java 中的异常应该是异常的。不要将它们用于正常的程序流程,手动进行边界检查。 IIRC 异常处理在 Java 中相当慢,这可能是您的问题的原因。话虽如此,我实际上并没有详细查看您的代码 - 对它如何做的高级描述会有所帮助。
  • @Dukeling 我尝试在该文件上运行该代码,但它只捕获 1 个异常。最重要的是,代码在 24 毫秒内完成,所以我想我们都想知道“我的高端游戏设备上的大量时间” 是什么意思。 --- 仅供参考: 它只产生一个异常的原因是迷宫完全封闭在墙壁中,因此从起点A 开始的 4 个可能步骤中只有一个会导致异常。

标签: java


【解决方案1】:

您的问题是visited 数组。

首先,一个小问题:visited 数组不应该是 Boolean[][]。只需将其设为boolean[][],它会自动初始化为所有false 值,这样也可以消除初始化循环。

现在,主要问题是 visited 没有标记为 true,直到您真正处理该点。这意味着同一点会被多次添加到队列中。

迷宫示例:

#####################
#...#...#...#...#...#
A.#1..#2..#3..#4..#5B
#...#...#...#...#...#
#####################

在这种情况下,点1 被两次添加到队列中。直到点2 的每个点也将被添加两次。点2会加4次,3加8次,4加16次,5加32次。

如您所见,每轮1 处理的队列项目数量呈指数级增长,每次多条路径相遇时都会加倍。

解决方案:visited重命名为queued,并在添加到队列的同时标记点true,从而防止多次添加同一个点。

结果:迷宫 3 的代码在不到 50 毫秒内完成。

1) “回合”是指处理距离起点(距离)更远的所有排队点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    相关资源
    最近更新 更多