我有一个由二维数组代表的迷宫。
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的房间。
答案 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的迷宫中在几分之一秒内正常工作。