题
假设您想要一个 N × M 网格上的简单迷宫,有一条路径通过,并且有大量死胡同,但这看起来“正确”(即就像有人手工制作的,没有太多微小的死角之类的)。有已知的方法可以做到这一点吗?
解决方案
从 http://www.astrolog.org/labyrnth/algrithm.htm
递归回溯器:这与下面描述的递归回溯求解方法有些关系,并且需要堆栈达到迷宫的大小。雕刻时,尽可能贪婪,如果当前单元格旁边有一个未制作的部分,则始终雕刻到未制作的部分。每次移动到新单元格时,将前一个单元格压入堆栈。如果当前位置旁边没有未制作的单元格,则将堆栈弹出到上一个位置。当您从堆栈中弹出所有内容时,迷宫就完成了。该算法导致迷宫具有尽可能高的“河流”系数,死胡同更少但更长,并且通常是非常长且曲折的解决方案。它运行得相当快,尽管 Prim 的算法要快一些。递归回溯不能用作墙加法器,因为这样做往往会导致沿着外部边缘的解决方案路径,其中迷宫的整个内部通过单个茎连接到边界。
他们只产生 10% 的死胡同
是该方法生成的迷宫的示例。
其他提示
一个非常简单的解决方案可能是将随机权重分配给图边并应用 克鲁斯卡尔算法 找到最小生成树。
关于迷宫生成算法的最佳讨论: http://www.jamisbuck.org/presentations/rubyconf2011/index.html (几天前在 HN 上)。
奇怪的是,通过稍微改变“规范”规则并从随机配置开始, 康威的生命游戏 似乎会生成非常漂亮的迷宫!
(我不记得确切的规则,但这是一个非常简单的修改,往往会“致密”细胞群......)
我最喜欢的方法是使用 Kruskal 算法,但是当随机选择并删除边缘时,根据其连接的边缘类型对选择进行加权。
通过改变不同边缘类型的权重,您可以生成具有许多不同特征或“个性”的迷宫。请参阅我的示例:
生成迷宫的方法之一是 Prim 算法的随机版本。
从充满墙壁的网格开始。选择一个单元格,将其标记为迷宫的一部分。将单元格的墙壁添加到墙壁列表中。虽然列表中有墙:
从列表中随机选择一面墙。如果对面的单元格尚未进入迷宫:
(i) 将墙设为通道,并将对面的单元格标记为迷宫的一部分。
(ii) 将单元格的相邻墙壁添加到墙壁列表中。
如果对面的单元格已经在迷宫中,则从列表中删除墙。
更多了解请点击 这里
这是用伪代码编写的 DFS 算法:
创建一个 CellStack (LIFO) 来保存单元位置列表
设置 TotalCells = 网格中的单元格数量
随机选择一个单元格并将其命名为 CurrentCell
设置已访问单元格 = 1
而访问cells <TotalCells发现所有墙壁都完好无损的CurrentCell的邻居
如果找到一个或多个随机选择一个
推倒它和 CurrentCell 之间的墙
将 CurrentCell 位置推送到 CellStack 上
使新单元格成为 CurrentCell
将1添加到访问室中,其他弹出了Cellstack的最新单元格
使其成为电流式Endif Endif Endif