给定一个基本网格(如一张方格纸),其中每个单元格都随机填充了 n 种颜色中的一种,是否有一种经过验证的真实算法可以告诉我哪些连续区域(相同的单元格组侧面连接的颜色)有吗?假设 n 是合理的,比如 5。
我有一些想法,但他们都觉得非常低效。
给定一个基本网格(如一张方格纸),其中每个单元格都随机填充了 n 种颜色中的一种,是否有一种经过验证的真实算法可以告诉我哪些连续区域(相同的单元格组侧面连接的颜色)有吗?假设 n 是合理的,比如 5。
我有一些想法,但他们都觉得非常低效。
最好的算法是 O(细胞数),与颜色的数量无关。
这可以通过遍历单元格来实现,每次访问尚未标记为已访问的单元格时,进行图遍历以找到该区域中的所有连续单元格,然后继续迭代。
编辑:
这是一个简单的深度优先搜索伪代码示例,这是一个易于实现的图遍历:
function visit(cell) {
if cell.marked return
cell.marked = true
foreach neighbor in cell.neighbors {
if cell.color == neighbor.color {
visit(neighbor)
}
}
}
除了递归的递归答案,如果递归太慢,您可以使用堆栈:
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
}
}
}
}
您可以尝试在每个方格上进行洪水填充。随着洪水的蔓延,将网格正方形记录在数组或其他东西中,并将它们涂上未使用的颜色,例如-1。
关于洪水填充的维基百科文章可能对您有用:http ://en.wikipedia.org/wiki/Flood_fill
Union-find也可以在这里工作。实际上,您可以将您的问题表述为关于图的问题:顶点是网格单元,如果两个顶点的网格单元具有相同的颜色,则它们是相邻的。您正在尝试查找连接的组件。
使用 union-find 数据结构的方式如下:首先创建一个 union-find 数据结构,其中包含与单元格一样多的元素。然后遍历单元格,union
如果它们具有相同的颜色,则遍历两个相邻的单元格。最后,find
在每个单元上运行并存储响应。具有相同颜色的单元格find
位于相同的连续彩色区域中。
如果您想要更细粒度的控制,您可能会考虑使用A*算法并使用启发式方法来包含类似颜色的图块。
您遍历扫描线中的区域,从左到右从上到下。对于每个单元格,您创建一个单元格列表,这些单元格在单元格之间共享为相同的内存对象。对于每个单元格,您将当前单元格添加到列表中(与其共享或创建)。然后,如果右侧或下方的单元格颜色相同,您将与该单元格共享该列表。如果该单元格已经有一个列表,则合并列表并将列表中列出的每个单元格中对列表对象的引用替换为新的合并列表。
然后位于每个单元格中的是对包含该单元格的每个连续单元格的列表的引用。这恰当地结合了每个单元之间的填充工作。而不是为每个单元格重复它。由于您有列表用合并的数据替换数据,因此只是迭代列表。它将是 O(n*c),其中 n 是单元格的数量,c 是图形连续性的度量。一个完全脱节的网格将是 n 次。一个完全连续的 1 颜色图,为 n^2/2。
我在视频中听到了这个问题,也在这里找到了它,我想出了我在搜索中看到的最佳方法。以下是算法的基本步骤:
<int,Dictionary<int,Hashset<cell>>>
用于在这些颜色中存储颜色和组。Hashset 包含单元格位置(具有 2 个属性的单元格对象:int 行、int 列)。这是我制作的带有视觉和完整解释的视频的链接: https ://d.tube/#!/v/israelgeeksout77/wm2ax1vpu3y
PS 我在 GeeksForGeeks 上找到了这篇文章https://www.geeksforgeeks.org/largest-connected-component-on-a-grid/
他们方便地以多种语言发布了这个问题的源代码!但是我尝试了他们的代码和我的代码,我的运行时间大约是 1/3。