我正在寻找一种算法或程序的一般方法,以验证是否可以从一组块构造某个形状。
对于像下面示例中的那样的一行单行块,可以将我们需要的形状转换为一个长行,并编写递归函数以按长度选择块。
但是,使用包含多行块的集合来解决此任务(检查构造形状的可能性)的一般方法是什么,如下例中的2x2平方?
答案 0 :(得分:2)
递归求解这种方法的一种方法是从黑白单元格的初始网格开始,重复确定一个特定的黑色网格单元格,并尝试覆盖(或" nibble off")该网格单元格一切都在可能的方式。例如:始终选择最底部,最右边的黑色网格单元格 - 也就是说,在当前子问题的所有最底部的黑色单元格中,选择最右边的单元格。
覆盖所选单元格的一些(实际上,大多数)展示位置可以立即被识别为无效,因为它们也覆盖了一些白色单元格 - 我们知道所有白色单元格都必须保持白色。如果没有"好"放置任何可用的片段(放置是"好"如果它覆盖所选择的单元格而没有白色单元格)那么我们可以为此子问题返回NO:它无法解决。 OTOH,如果至少有一个"好"放置一个可用的部分,它可能会或可能不会导致解决方案:处理这个,每个这样的"好"放置产生子问题,其中对应于放置的片的黑色单元已被删除(即,变为白色),并且刚刚放置的片段类型的可用片段的数量减少了一个。当没有黑色单元格时会出现一个基本情况:在这种情况下我们可以返回YES,因为我们知道可以放置碎片以实现空网格(具体来说,这包括根本不放置任何碎片)。 / p>
这种递归方法可能会多次重新审视一些子问题。例如,如果原始网格的一部分包含4x2块黑色单元格,并且您至少有以下2个单元格可用:
XX 2 Y 2
Y
然后您可以通过以下方式填充该4x2块
XXYY YXXY YYXX
XXYY YXXY YYXX
因此产生的子问题(缺少这个4x2块并且每种类型的块少2个)将被解决3次不同的时间。为避免这种情况,在某些(相当严格的)情况下,您可以使用自上而下的动态编程(也称为memoisation)。这具有解决每个子问题最多一次的效果,但(可能)需要将答案(每个单个位,表示是或否)存储到所有可能的子问题,其中有2 ^(m) * n)*(k_1 + 1)*(k_2 + 1)* ... *(k_t + 1),其中m和n是网格的宽度和高度,k_1,...,k_t是数字t种不同类型的可用副本。实际上,这意味着大于约5 * 5的问题将无法解决(至少如果你使用"显而易见的"网格编码,其中每个单元格成为整数中的单个位;它&# 39;可能有可能提出一种更经济的编码,只需要2 ^ b位,其中b是最初的黑色单元的总数,而不是整个单元的总数)。 (OTOH,如果你准备假装每种类型的作品数量不限,你只需要存储2 ^(m * n)个答案,因为我们不需要跟踪每件作品保留多少。这可以作为快速首次检查有用:如果即使每种类型的作品数量不受限制也无法解决问题,那么它肯定无法通过有限的方式解决它们的数量。)