查找2D网格中的所有循环/封闭形状

hel*_*on3 10 c# algorithm grid 2d

我有一个"无限"的2D网格,我想要检测封闭/完整的"结构" - 任何形状的区域,四周都是封闭的.但是,我需要确定每个闭路 - 包括更大的形状,如果有的话.

在研究这个时,我发现了循环检测算法,但我没有看到一个干净/有效的方法将较大的电路与较小的电路分开.

例如,给出以下两个"完整"结构:

0 1 1 1 0
0 1 0 1 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 1 1
0 1 0 1 0 1
0 1 1 1 1 1
Run Code Online (Sandbox Code Playgroud)

第一个是由8"墙"包围的单个细胞.循环检测使得检测它变得微不足道.

第二个例子包含两个例子,但它们共用一面墙.我关心的是三个独立的电路 - 左侧房间,右侧房间和整体结构.

循环算法的多次传递可能有效,但我必须确定我没有回溯已经找到的形状.

我也看过洪水填充算法,但似乎它假设你已经知道有界区域内的一个点.对于无限的2D网格,如果它不在有效的结构中,我需要一个大小限制来强制它放弃.

有没有我缺少的解决方案或我错过了我的想法?

我只会在添加边界值时"检查".使用上面的例子,如果我改变任何0 - > 1,可能已经创建了一个新的循环,我将运行逻辑.我不关心识别单独的结构,并且总是有一个原点坐标.

我一直在研究这里发布的解决方案,但它们都基于已经知道哪些节点连接到其他节点.我已经玩弄了识别每条"线"的逻辑,我可以继续从那里开始,但感觉多余.

Spe*_*tre 5

我会这样做:

0 0 0 0 0 0 0
0 1 1 1 1 1 0
0 1 0 1 0 1 0
0 1 1 1 1 1 0
0 0 0 0 0 0 0
Run Code Online (Sandbox Code Playgroud)
  1. 填充背景 2

    要确定您是否在背景中,只需投射光线并计算随后的零点。一旦你找到光线长度大于电路尺寸限制的位置,你就得到了起点。

    [0]0-0-0-0-0-0
     0 1 1 1 1 1 0
     0 1 0 1 0 1 0
     0 1 1 1 1 1 0
     0 0 0 0 0 0 0
    
     2 2 2 2 2 2 2
     2 1 1 1 1 1 2
     2 1 0 1 0 1 2
     2 1 1 1 1 1 2
     2 2 2 2 2 2 2
    
    Run Code Online (Sandbox Code Playgroud)

    不要为此使用未绑定的递归洪水填充!!!因为对于“无限”区域,您将堆栈溢出。您可以限制递归级别,如果达到而不是递归添加点到某个队列以供以后进一步处理。这通常会大大加快速度并限制堆栈使用...

  2. 先找 0

     2 2 2 2 2 2 2
     2 1 1 1 1 1 2
     2 1[0]1 0 1 2
     2 1 1 1 1 1 2
     2 2 2 2 2 2 2
    
    Run Code Online (Sandbox Code Playgroud)
  3. 洪水填满它 3

     2 2 2 2 2 2 2
     2 1 1 1 1 1 2
     2 1 3 1 0 1 2
     2 1 1 1 1 1 2
     2 2 2 2 2 2 2
    
    Run Code Online (Sandbox Code Playgroud)
  4. 选择所有1附近3

    这是你的电路。如果您在填充#3 时记得 bbox,那么您只需要扫描每侧一个单元格放大的区域...选定的单元格是您的电路。

     2 2 2 2 2 2 2
     2 * * * 1 1 2
     2 * 3 * 0 1 2
     2 * * * 1 1 2
     2 2 2 2 2 2 2
    
    Run Code Online (Sandbox Code Playgroud)
  5. 洪水填充32

    这将避免使用已经处理过的电路

     2 2 2 2 2 2 2
     2 1 1 1 1 1 2
     2 1 2 1 0 1 2
     2 1 1 1 1 1 2
     2 2 2 2 2 2 2
    
    Run Code Online (Sandbox Code Playgroud)
  6. 循环#2,而任何0找到

  7. 全部改20

     0 0 0 0 0 0 0
     0 1 1 1 1 1 0
     0 1 0 1 0 1 0
     0 1 1 1 1 1 0
     0 0 0 0 0 0 0
    
    Run Code Online (Sandbox Code Playgroud)


Tob*_*zel 2

从问题的图论角度来看,您可以将映射的每个 0 解释为一个节点,相邻的 0 通过一条边连接。在我看来,你想要做的是计算该图的连接组件(也许它们的连接性为 1 值,以找到相同结构的“相邻房间”)

如果您只想计算一次此信息,则使用并查找数据结构的union简单方法就足够了,即每个边应用一次。

如果您想动态编辑地图,基于图形模型的最佳方法可能是一些支持splitde-union操作的动态数据结构,例如参见此处此处