如何最佳解决洪水填充难题?

Posted

技术标签:

【中文标题】如何最佳解决洪水填充难题?【英文标题】:How to optimally solve the flood fill puzzle? 【发布时间】:2010-11-28 16:38:34 【问题描述】:

我喜欢玩益智游戏 Flood-It,可以在线玩:

https://www.lemoda.net/javascript/flood-it/game.html

它也可以作为 iGoogle 小工具使用。目的是用最少的连续洪水填充来填充整个棋盘。

我正在尝试编写一个程序来最佳地解决这个难题。解决这个问题的最佳方法是什么?理想情况下,我想使用 A* 算法,但我不知道估计剩余步数的函数应该是什么。我确实编写了一个程序,该程序进行了深度 4 蛮力搜索以最大化填充区域。它运行得相当好,并且在解决难题方面击败了我,但我对那个算法并不完全满意。

有什么建议吗?提前致谢。

【问题讨论】:

问题似乎是 NP 难题:Bristol University link 【参考方案1】:

我认为您可以考虑匹配或不匹配当前颜色的正方形的数量。因此,您对“距离”的启发式测量将是棋盘上与您选择的颜色不同的方格数,而不是步数。

【讨论】:

【参考方案2】:

一个简单的启发式方法可能是使用剩余的颜色数(减 1) - 这是可以接受的,因为至少需要多次点击才能清除棋盘。

【讨论】:

【参考方案3】:

作为一种启发式方法,您可以构建一个图,其中每个节点代表一组连续的、相同颜色的正方形,并且每个节点都连接到它所接触的那些。 (每条边的权重为 1)。然后,您可以使用寻路算法来计算从左上角到所有其他节点的“距离”。然后,通过使用其他 5 种颜色中的每一种查看填充填充的结果,确定哪一种可以最小化到“最远”节点的距离,因为这可能是您的瓶颈。

将该计算的结果添加到目前已完成的填充数中,并将其用作您的 A* 启发式。

【讨论】:

【参考方案4】:

A* 只是一个优先的图搜索。每个节点都是一个游戏状态,您根据一些启发式对节点进行排名,并始终扩展最低预期最终成本节点。只要您的启发式方法没有低估成本,就保证您找到的第一个解决方案是最优的。

玩了几次游戏后,我发现尝试钻到对面的角落然后所有的角落往往会导致胜利。因此,一个好的起始成本估算将是(到目前为止的成本)+足够数量的填充以到达对角[注意:不是最低限度,就足够了。只是贪婪地向角落填充以计算启发式]。

【讨论】:

【参考方案5】:

一种天真的“贪婪”算法是选择使主要区域的整体周长最大化的下一步。

(我的几个聪明的朋友前几天正在考虑这个问题,并决定优化可能是 NP 难的(例如,你必须暴力破解) - 我不知道他们是否正确(当时不在听听推理,我自己还没有考虑过)。)

请注意,对于计算步骤,我认为 union-find 算法是您的朋友,它使计算“一步”非常快(参见例如this blog post)。

【讨论】:

NP-Hard 并不意味着你必须暴力破解它。【参考方案6】:

我不确定,但我相当肯定这可以贪婪地解决。您正在尝试将颜色字段的数量减少到 1,因此较早减少更多颜色字段的效率不应低于早期减少更少颜色字段的效率。

1) 定义一组现有的同色组。

2) 对于每个集合,按颜色计算相邻集合的数量。具有单一颜色的相邻集合的最大计数是该集合的权重。

3) 使用单一颜色获取具有最多邻居数的集合,并将其填充为该颜色。合并集合,并为受合并影响的所有集合(合并集合的所有新邻居)更新排序。

总的来说,我认为这实际上应该在 O(n log n) 时间内计算,其中 n 是像素数,而 log(n) 仅来自维护排序的权重列表。

我不确定当多个字段具有相同权重时是否需要打破平局。也许决胜局会选择地图上大多数群体的共同颜色。

无论如何,请注意游戏的目标是减少不同颜色区域的数量,而不是最大化周边,因为不同的配色方案有时会使较大的区域成为次优选择。考虑领域:

3 3 3 3 3

1 1 1 1 1

1 1 1 1 1

2 2 2 2 2

1 2 2 2 2

颜色 1 具有最大的周长,但颜色 2 是最佳选择。

编辑>

从头开始。例子:

3 1 3 1 3

1 1 1 1 1

1 1 1 1 1

2 2 2 2 2

1 2 2 2 2

使我自己的贪心算法无效。但我不相信这是一个简单的图遍历,因为更改为 2 个邻居共享的颜色会访问 2 个节点,而不是 1 个。

颜色消除应该在启发式中发挥一些作用。

1) 使用图表上尚未出现的颜色进行填充是不正确的。

2) 如果有一个颜色字段具有唯一的颜色,则至少需要对其进行一次填充。它不能与任何其他填充物捆绑在一起。我认为这意味着尽早填充它是安全的。

3) 用于相邻字段计数的贪心算法对于 2 色地图是有意义的。

【讨论】:

【参考方案7】:

玩了几次游戏后,我注意到一个好的策略是始终“深入”,选择最深入未淹没区域的颜色。

【讨论】:

【参考方案8】:

这是实现图表以支持Smashery's heuristic 的想法。

在disjoint set 中表示每组连续的同色方块,以及相邻方块组的列表。泛洪填充将一个集合与其所有相邻集合合并,并合并邻接列表。这种隐式的图形结构可以让你找到从左上角到最远节点的距离。

【讨论】:

【参考方案9】:

我一直在研究这个问题,在我的求解器开始工作后,我查看了其他人采用的方法。

大多数求解器都是启发式的,不能保证最优性。启发式方法着眼于未选择的方格数量和颜色分布,或到“最远”方格的距离。将良好的启发式算法与有界 DFS(或带前瞻的 BFS)相结合,可以得到对于标准 14x14 网格相当快的解决方案。

我采取了一种稍微不同的方法,因为我有兴趣找到可证明的最佳路径,而不仅仅是一条“好”的路径。我观察到搜索空间实际上比搜索树的分支因子增长得慢得多,因为有很多重复的位置。 (因此,在深度优先策略中,保持历史记录以避免重复工作很重要。)有效分支因子似乎更接近 3 而不是 5。

我采取的搜索策略是将 BFS 执行到“中点”深度,在该深度中状态数将变得不可行,最好在 11 到 13 步之间进行。然后,我在中点深度检查每个状态,并以它作为根开始执行新的 BFS。这两种 BFS 搜索都可以通过消除在先前深度中找到的状态来修剪,而后一种搜索可以受最知名解决方案的深度限制。 (应用于第二步中检查的子树顺序的启发式方法可能也会对一些人有所帮助。)

另一种被证明是快速求解器关键的修剪技术是简单地检查是否有超过 N 种颜色,如果您距离当前最佳解决方案只有 N 步或更少步。

一旦我们知道哪个中点状态在通往最优解的路径上,程序就可以使用该中点状态作为目标执行 DFS(并修剪选择不在中点的正方形的任何路径。)或者,它可能是在 BFS 步骤中构建路径是可行的,但会消耗一些额外的内存。

我的求解器速度不是很快,但它可以在几分钟内找到有保证的最优解。 (见http://markgritter.livejournal.com/673948.html,或http://pastebin.com/ZcrS286b的代码。)

【讨论】:

【参考方案10】:

Smashery's answer 可以稍微调整一下。对于总移动次数估计,如果在最大距离处有“k”种颜色,则将“k-1”添加到移动估计次数。

更一般地,对于每种颜色,请考虑可以清除该颜色的最大距离。这为我们提供了一个字典,将一些最大距离映射到可以在该距离清除的非零颜色数。将所有键的 value-1 相加,并将其与最大距离相加,以获得移动次数估计值。

此外,还有一些免费的案例。如果在任何时候我们可以在一个动作中清除一种颜色,我们就可以在不考虑其他动作的情况下进行该动作。

【讨论】:

尽管我的评论有负面评价;我已经通过这些调整实现了算法,并且可以在查看大约 10,000 个节点时解决典型的 14x14 板。我不清楚为什么显着改善下限估计的技术会被否决。尤其是当一些劣质的启发式(贪婪,剩下的颜色)没有被否决时。

以上是关于如何最佳解决洪水填充难题?的主要内容,如果未能解决你的问题,请参考以下文章

iPad绘画应用程序上的递归洪水填充

1062. 洪水填充(经典)

当使用洪水填充算法填充颜色后绘制线条时,填充颜色消失

iPad 中的洪水填充太慢了

洪水填充图像的图像处理

使用matlab进行洪水填充