使用DFS的迷宫生成失败,我不知道为什么

时间:2013-07-02 01:49:07

标签: java algorithm graph depth-first-search maze

我只想使用最简单的算法生成一些迷宫,但我的迷宫看起来像下面这样:

My maze

这是一段Java代码(whatVisit函数工作正常,不要看它):

private void dfs(Point start, boolean[][] visited) {
    Point nextCell = whatVisit(start, visited);
    if(nextCell == null)        // if there's nothing to visit
        return;

    // mark current cell as visited
    visited[start.y][start.x] = true;
    // destroy the wall between current cell and the new one
    borders[(start.y + nextCell.y)/2][(start.x + nextCell.x)/2] = true;

    // start a new search from found cell
    dfs(nextCell, visited);
}

private Point whatVisit(Point p, boolean[][] visited) {
    Vector<Point>cells = new Vector<Point>();   // to store acessible cells

    // lookaround
    if(p.x - 2 >= 0 && !visited[p.y][p.x - 2])
        cells.add(new Point(p.x - 2, p.y));
    if(p.x + 2 < visited[0].length && !visited[p.y][p.x + 2])
        cells.add(new Point(p.x + 2, p.y));
    if(p.y - 2 >= 0 && !visited[p.y - 2][p.x])
        cells.add(new Point(p.x, p.y - 2));
    if(p.y + 2 < visited.length && !visited[p.y + 2][p.x])
        cells.add(new Point(p.x, p.y + 2));

    // instead of Random
    Collections.shuffle(cells);

    // returns null if there are no acessible cells around
    if(cells.size() > 0)
        return cells.get(0);
    else return null;
}

我知道为什么它不起作用!当DFS最终到达没有可访问单元格的地方时,它就会重新开始。

如何解决此问题并强制正确使用?

感谢。

2 个答案:

答案 0 :(得分:1)

实际上我仍然没有得到你想要产生的迷宫的目的。但我有一些建议:

  1. 通过随机化坐标创建dfs算法的2或3个起点,这样迷宫就不会单调。

  2. 在您的算法中,每次移动只能尝试1个可访问的单元格。尝试在每次移动中访问更多可访问的单元格,以使路径不是完成的单向路径。 (这也是你的dfs在找不到可访问的单元后重新开始的原因)

  3. 以下是我上面第二个想法的代码(根据您上面的代码编辑):

    private void dfs(Point start, boolean[][] visited) {
        ArrayList<Point> nextCell = whatVisit(start, visited);
        if(nextCell == null)        // if there's nothing to visit
            return;
    
        // mark current cell as visited
        visited[start.y][start.x] = true;
    
        for (Point next : nextCell) // try new accessible cells
        {
            // destroy the wall between current cell and the new one
            borders[(start.y + next.y)/2][(start.x + next.x)/2] = true;    
            // start a new search from found cell
            dfs(next, visited);
        }
    }
    
    private ArrayList<Point> whatVisit(Point p, boolean[][] visited) {
        Vector<Point>cells = new Vector<Point>();   // to store acessible cells
    
        // lookaround
        if(p.x - 2 >= 0 && !visited[p.y][p.x - 2])
            cells.add(new Point(p.x - 2, p.y));
        if(p.x + 2 < visited[0].length && !visited[p.y][p.x + 2])
            cells.add(new Point(p.x + 2, p.y));
        if(p.y - 2 >= 0 && !visited[p.y - 2][p.x])
            cells.add(new Point(p.x, p.y - 2));
        if(p.y + 2 < visited.length && !visited[p.y + 2][p.x])
            cells.add(new Point(p.x, p.y + 2));
    
        // returns null if there are no accessible cells around
        if(cells.size() > 0)
        {
            ArrayList<Point> tmp = new ArrayList<Point>();
            // randomize how many cell that will be returned
            int x = (int)(Math.random()*cells.size()) + 1;
            if (x > cells.size())
                x = cells.size();
            Collections.shuffle(cells);
            for (int i = 0; i < x; i++)
                tmp.add(cells.get(i));
            return tmp;
        }
        else return null;
    }
    

    希望这会有所帮助;)

答案 1 :(得分:1)

看起来你只是在你到达死胡同时拯救并退出。相反,您应该回溯直到找到仍然具有可访问邻居的单元格,并从那里继续算法。通常的方法是使用堆栈:在您访问它们时按下项目,弹出以回溯。像这样:

if (nextCell == null) { // You've reached a dead-end
  if (stack.empty()) // base-case, bail out
    return;

  dfs(stack.pop(), visited); // backtrack
} else {
  stack.push(nextCell);

  visited[start.y][start.x] = true;
  borders[(start.y + nextCell.y)/2][(start.x + nextCell.x)/2] = true;
  dfs(nextCell, visited);
}