Algorithm 是否有一种算法来确定网格中连续的彩色区域?
给定一个基本网格(如一张图表纸),其中每个单元格随机填充了n种颜色中的一种,是否有一种经过验证的算法可以告诉我有哪些相邻区域(在侧面连接的相同颜色的单元格组)?假设n是合理的,比如5Algorithm 是否有一种算法来确定网格中连续的彩色区域?,algorithm,cellular-network,Algorithm,Cellular Network,给定一个基本网格(如一张图表纸),其中每个单元格随机填充了n种颜色中的一种,是否有一种经过验证的算法可以告诉我有哪些相邻区域(在侧面连接的相同颜色的单元格组)?假设n是合理的,比如5 我有一些想法,但都觉得效率太低了。你可以试着在每个广场上填充洪水。当洪水蔓延时,将网格正方形记录在一个数组或其他东西中,并用一种未使用的颜色(例如-1)给它们上色。最好的算法是O(单元数),与颜色数无关 这可以通过迭代单元格来实现,每次访问未标记为已访问的单元格时,执行图形遍历以查找该区域中的所有连续单元格,然后继
我有一些想法,但都觉得效率太低了。你可以试着在每个广场上填充洪水。当洪水蔓延时,将网格正方形记录在一个数组或其他东西中,并用一种未使用的颜色(例如-1)给它们上色。最好的算法是O(单元数),与颜色数无关 这可以通过迭代单元格来实现,每次访问未标记为已访问的单元格时,执行图形遍历以查找该区域中的所有连续单元格,然后继续迭代 编辑: 下面是深度优先搜索的简单伪代码示例,这是一种易于实现的图形遍历:
function visit(cell) {
if cell.marked return
cell.marked = true
foreach neighbor in cell.neighbors {
if cell.color == neighbor.color {
visit(neighbor)
}
}
}
Wikipedia关于洪水填充的文章可能对您有用:除了递归的递归答案外,如果递归太慢,您还可以使用堆栈:
function visit(cell) {
stack = new stack
stack.push cell
while not stack.empty {
cell = stack.pop
if cell.marked continue
cell.marked = true
foreach neighbor in cell.neighbors {
if cell.color == neighbor.color {
stack.push neighbor
}
}
}
}
我也会在这里工作。事实上,您可以将问题表述为一个关于图形的问题:顶点是网格单元,如果两个顶点的网格单元具有相同的颜色,则两个顶点是相邻的。您正在尝试查找连接的组件
使用union find数据结构的方法如下:首先创建一个union find数据结构,其元素数量与单元数量相同。然后遍历单元格,如果两个相邻单元格的颜色相同,则将其合并。最后,在每个单元格上运行
find
,并存储响应。具有相同的查找的单元格位于相同的连续彩色区域。如果您想进行更精细的控制,可以考虑使用该算法并使用启发式包含类似颜色的分片。您在扫描线中迭代区域,从左到右从上到下。对于每个单元格,您将在单元格之间创建一个共享为同一内存对象的单元格列表。对于每个单元格,将当前单元格添加到列表中(与其共享或创建)。然后,如果右侧或下方的单元格颜色相同,则与该单元格共享该列表。如果该单元格已经有列表,则可以合并列表,并将列表中列出的每个单元格中对列表对象的引用替换为新的合并列表
然后,每个单元格中都有一个对列表的引用,该列表包含每个与该单元格相邻的单元格。这适当地结合了每个单元之间的溢流填充工作。而不是对每个单元格重复它。因为有列表,所以用合并的数据替换数据只是在列表中迭代。它将是O(n*c),其中n是单元数,c是图形连续程度的度量。一个完全脱节的网格将在n次。一个具有n^2/2的完全连续的单色图。您能比“执行图遍历”更具体一点吗?这是递归的吗?图形遍历将是一个洪水填充,正如其他一些答案所述。呃,深度优先搜索是一个非常糟糕的主意;很容易耗尽堆栈空间。请改为广度优先搜索(或维护您自己的堆栈)/根据定义,图遍历位于单元迭代的顶部,这不是O(n)。@Tatarize否,即使在一个简单的实现中,只要图遍历和单元迭代在相同的数据结构上运行,它也是O(n)。图的遍历是O(e),但对于平面图来说是O(n)。我认为这个想法是为矩阵(图)中的每个单元格调用visit(cell)
,然后确定每个颜色的哪个连通区域最大。