如何在迷宫中找到最佳墙壁以产生最大面积?

时间:2013-11-21 22:48:20

标签: algorithm language-agnostic graph-theory

我有一个由二维数组代表的迷宫。

bool[][] maze = ...

如果该位置有墙,则maze[row][column]为True,如果该位置没有墙,则为False。周边总是被墙围住。

目标是确定最大的房间,然后在迷宫中找到一个切割点,如果你在那个时候打破墙壁,将会创建新的最大房间。

是否有算法可以找到可以创建最大空间的墙?

是否应该将其建模为图表?

编辑:

我随意地扔在房间里。房间是一个或多个连接在一起的非墙壁。

----------
|   |    |
|   |----|
|   |    |
----------

maze = { {True, True, True, True, True},
         {True, False, True, False, True},
         {True, False, True, True, True},
         {True, False, True, False, True},
         {True, True, True, True, True} }

此图包含三个房间。它们的区域是3,1和1.最佳切割点可以是(1,2)(3, 2)。这些中的任何一个都会产生面积为5的房间。

3 个答案:

答案 0 :(得分:3)

Union-find似乎是一个合适的算法。

只需遍历网格并将每个非墙单元与其非墙邻居联合起来。

然后遍历集合找到最大的一个(这是最大的房间)。

然后再次穿过网格,对于每个墙,检查墙的不同侧面的联合大小(只记录大小,不实际执行联合)。记录最多的联盟将表明墙壁会破裂以创造最大的空间。

对于所有远程实用的网格大小,使用已知的优化进行union-find的运行时间为O(rowCount*columnCount)(线性)。

答案 1 :(得分:1)

立即想到的方法是强力,在这种情况下效率不是太低,因为它只需要多项式时间。只需尝试删除每个部分,看看哪个部分创建了最大的房间。

以下是一些使用此方法的伪代码

int[] removeBestWall(maze) {
  int maxSize = 0;
  int[] bestWall = [0, 0]
  for(int i = 1; i < maze.width - 1; i++) {
    for(int j = 1; j < maze.height - 1; j++) {
      int size = getRoomSize(maze, i, j);
      if(size > maxSize) {
        maxSize = size;
        bestWall = [i, j];
      }
    }
  }
  return bestWall;
}

int getRoomSize(maze, i, j) {
  if(maze[i][j] == True) return 0;
  int size = 1;
  bool[][] newMaze = make;
  newMaze[i][j] = True;
  return size + 
   getRoomSize(newMaze, i, j + 1) +
   getRoomSize(newMaze, i, j - 1) +
   getRoomSize(newMaze, i + 1, j) +
   getRoomSize(newMaze, i - 1, j);
}

答案 2 :(得分:1)

我同意您展示的数据结构含糊不清。你真的想要两个阵列:一个用于水平墙,一个用于垂直。另一种布局方式是作为一个单元结构数组,其中每个结构的右壁和底壁都有一个布尔值。

由于您总是在两个房间之间寻找一面墙,这相当于找到总面积最大的两个相邻房间。首先确定房间并列出清单。这是通过对开放广场森林的深度或广度的首次搜索。森林的每个连通组件都是一个房间。该区域是组件中的方块数。

接下来,您需要知道哪些房间共用每面墙。这只是环绕所有内墙并找到与其相邻的房间的问题。然后,您将拥有一份墙壁列表和两个相关的房间。

最后,遍历此列表并选择相邻房间的墙,总面积最大。

有很多方法可以快速进行这种计算,但除非蛮力基准测试太慢,否则这是不成熟的优化。我相信这可以在500x500的迷宫中在几分之一秒内正常工作。