我有一个3D“立方体”矩阵,其中一些单元格填满,其他单元格为空。由填充的细胞包围的封闭区域表示中空形状。例如,矩阵可以以这样的方式填充单元,使得它们一起形成空心球的表面。现在,我想要一种有效的方法来填充这个球体的内部:如果一个单元格C0
被填充的单元格在所有方向上包围(任何方向上的填充单元格都不需要是C0
的直接邻居) ,然后填写C0
。
一种天真的方式如下: -
对于每个单元格,扫描+ X,-X,+ Y,-Y,+ Z,-Z方向,然后查看 如果你在每个方向都遇到一个充满细胞的细胞。
如果在每个方向遇到填充的单元格,则填写此单元格 细胞(因为它是某种形状内部的一部分)。
如果你在一个方向上到达网格的末端而没有遇到任何填充 细胞,然后考虑的细胞不是任何形状的内部, 并且应该保持未填充状态。
上述方法的复杂性为O(n^4)
,其中3D网格的维度为n*n*n
。
优化可以如下: -
如果对于未填充的单元格C [x] [y] [z],我们遇到一个填充的单元格 在所有6个方向中,不仅C [x] [y] [z]需要 填补后,我们也会保证扫描所有细胞 刚才(即{in + X方向,所有单元格C [x] [y] [z],C [x + 1] [y] [z], C [x + 2] [y] [z],......,直到第一个填充的单元格},类似于-X,+ Y, -Y,+ Z,-Z方向)必须是某种形状内部的一部分,因此必须填充。
另一个可能如下: -
如果对于未填充的单元格C [x] [y] [z],我们不会遇到任何填充 例如,+ X方向的单元格,那么不仅C [x] [y] [z]将保留 未填充,也保证我们扫描的所有细胞 刚才(即在+ X方向,所有单元格C [x] [y] [z],C [x + 1] [y] [z], C [x + 2] [y] [z],......,直到网格结束)必须是外部的一部分 因此,必须保持未填充状态。
有人可以提出一个更有效的方法解决这个问题吗?即使是像上面这样简单的优化,也可能不会减少时间复杂度的顺序,这是值得欢迎的。
答案 0 :(得分:2)
您正在处理3D Flood Fill。查看详细的维基百科文章http://en.m.wikipedia.org/wiki/Flood_fill
答案 1 :(得分:1)
好的,因为这是一个封闭的空心形状,我们只需使用BFS或DFS来解决问题。
BFS:
从空队列开始,将任何位于内部空心形状的单元格添加到队列中。从队列的顶部,弹出一个单元格,填充此单元格并检查此单元格的其他6个邻居,如果未填充此邻居,则将其添加到队列中,否则只需忽略此单元格。继续此过程,直到队列为空。
剩下的问题是找到一个位于空心形状内的单元格,一个技巧就是你需要找到位于形状一角的单元格,它至少有三个填充的邻居
时间复杂度为O(填充单元格所需的数量* 6方向需要检查)
提示移至6方向:
int[] x = {0,0,0,0,1,-1};
int[] y = {0,0,1,-1,0,0};
int[] z = {1,-1,0,0,0,0};
Point p = // point in space with three dimension x,y,z
for(int i = 0; i < 6; i++){
int a = p.x + x[i];
int b = p.y + y[i];
int c = p.z + z[i];
}
答案 2 :(得分:0)
对于每个单元格,扫描+ X,-X,+ Y,-Y,+ Z,-Z方向,看看是否在每个方向都遇到填充单元格。
如果在每个方向遇到填充的单元格,则填充此单元格(因为它是某个形状内部的一部分)。
除非您只处理convex hulls,否则上述声明不正确。下图显示有问题的点未包含在蓝色形状中,但仍会在所有(x,y,z)方向上相交。
相反,要处理查找挖空形状的一般情况,可以将所有单元格添加到Set中。然后从边界单元开始。如果填充边界处的单元格是空心形状的一部分,否则它是背景(非填充)形状的一部分。
然后,类似于@Pham Trung的回答,你可以向各个方向向外移动,直到你遍历了形状内的所有细胞,忽略边界处的有色细胞。在前一个形状的边界处选择另一个单元格,然后开始该过程,直到遍历所有单元格。
最后,您将每个单元格标记为空心形状或背景的一部分。
答案 3 :(得分:0)
为了完整,还有两个。 YMMV取决于很多因素。
<强> 1。找到表面
如果您正在处理大量体素,一种优化可能性是找到空心的边界表面。这可以像Pham Trung的答案那样完成,但只接受至少填充了6个邻居中的一个的单元格。
确定边界表面后,可以使用1D填充逐行填充,作为方向&#34;内部&#34;和&#34;外面&#34;众所周知。
如果你有大量的体素(比例为n ^ 2而不是n ^ 3),这种方法可以使设置的体积小得多。设置查找通常非常快,但如果设置不适合RAM,它们会慢下来。
<强> 2。切片到2D
另一种可能性是将形状切割成2D切片并逐层连接所得到的腔。然后,只需要将两个切片同时保存在内存中。
主要思想是为每个单独连接的2D区域提供自己的标识符,然后找到它与相邻层中已知区域的连接。处理完所有图层后,将保留连接的3D区域。
具有挑战性的部分是找到连接相邻层中2D区域的最佳算法。看起来这种方法很快就具有简单的形状(2D切片中的连接区域很少)但是复杂的形状很慢(&#34;树中的虫洞和#34;)。此外,需要一种快速算法来找到两组中的单个公共点。 (即,不需要完整的集合交集,只需要有关集合是否至少有一个公共点的信息。)
同样,如果您的集合大小合理,那么Pham Trung描述的平凡算法可能是最佳选择。