Algorithm 检查是否可以从一组块构造二维形状

Algorithm 检查是否可以从一组块构造二维形状,algorithm,geometry,2d,shapes,plane,Algorithm,Geometry,2d,Shapes,Plane,我正在寻找一种算法或一种程序的通用方法,以验证某个形状是否可以由一组块构成 对于下面示例中的一组单线块,可以将所需的形状转换为一条长线,并编写一个递归函数,用于根据块的长度选择块 但是,用一个包含多行块的集合(如下面示例中的2x2正方形)来解决此任务(检查构造形状的可能性)的一般方法是什么 递归解决这个问题的一种方法是从黑白单元格的初始网格开始,反复确定一个特定的黑色网格单元格,并尝试以所有可能的方式覆盖(或“蚕食”)该网格单元格。例如:始终选择最底部、最右侧的黑色网格单元——也就是说,在当前

我正在寻找一种算法或一种程序的通用方法,以验证某个形状是否可以由一组块构成

对于下面示例中的一组单线块,可以将所需的形状转换为一条长线,并编写一个递归函数,用于根据块的长度选择块

但是,用一个包含多行块的集合(如下面示例中的2x2正方形)来解决此任务(检查构造形状的可能性)的一般方法是什么


递归解决这个问题的一种方法是从黑白单元格的初始网格开始,反复确定一个特定的黑色网格单元格,并尝试以所有可能的方式覆盖(或“蚕食”)该网格单元格。例如:始终选择最底部、最右侧的黑色网格单元——也就是说,在当前子问题中所有最底部的黑色网格单元中,选择最右侧的网格单元

一些(实际上,大多数)覆盖所选细胞的片段放置可以立即被识别为无效,因为它们也覆盖了一些白细胞——我们知道所有白细胞必须保持白色。如果没有任何可用工件的“良好”放置(如果一个放置覆盖了所选单元格且没有白色单元格,则该放置为“良好”),那么我们可以对此子问题返回“否”:这是不可能解决的。o如果一个可用工件至少有一个“良好”位置,则可能会或可能不会导致解决方案:为了处理这个问题,每个“良好”位置都会生成一个子问题,其中与该放置工件对应的黑色单元格已被删除(即变白),而刚放置的工件类型的可用工件数量减少了一个。基本情况发生在没有黑色单元格的情况下:在这种情况下,我们可以返回YES,因为我们知道可以放置碎片以实现空网格(具体来说,这涉及到根本不放置碎片)

这种递归方法可能会多次重新讨论某些子问题。例如,如果原始网格的一部分包含一个4x2的黑色单元格块,并且您至少有以下两个可用的单元格块:

XX  2         Y  2
              Y
然后,您可以用以下方式填充4x2块

XXYY       YXXY       YYXX
XXYY       YXXY       YYXX

因此产生的子问题(缺少这个4x2块,每种类型的工件少2个)将被解决3次。为了避免这种情况,在某些(相当严格的)情况下,您可以使用自顶向下的动态编程(也称为记忆)。这可以最多解决一次每个子问题,但(可能)需要存储所有可能子问题的答案(每个答案都是一个位,表示是或否),其中有2^(m*n)*(k*u 1+1)*(k*u 2+1)*…*(k*u t+1),其中m和n是网格的宽度和高度,k*u 1。。。,k_t是不同类型作品的可用拷贝数。在实践中,这意味着大于5*5的问题将无法解决(至少如果你使用“明显的”网格编码,其中每个单元成为整数中的一个位;可能会提出一种更经济的编码,只需要2^b位,其中b是初始黑色单元的总数,而不是整个单元的总数)。(OTOH,如果你准备假装每种类型的作品数量不限,你只需要存储2^(m*n)答案,因为我们不需要记录每件物品的剩余数量。这可能有助于快速进行第一次检查:如果即使每种物品数量不限,问题也无法解决,那么使用有限数量的物品肯定无法解决。)

递归解决这个问题的一种方法是从黑白单元格的初始网格开始,反复确定一个特定的黑色网格单元格,并尝试以所有可能的方式覆盖(或“蚕食”)该网格单元格。例如:始终选择最底部、最右侧的黑色网格单元——也就是说,在当前子问题中所有最底部的黑色网格单元中,选择最右侧的网格单元

一些(实际上,大多数)覆盖所选细胞的片段放置可以立即被识别为无效,因为它们也覆盖了一些白细胞——我们知道所有白细胞必须保持白色。如果没有任何可用工件的“良好”放置(如果一个放置覆盖了所选单元格且没有白色单元格,则该放置为“良好”),那么我们可以对此子问题返回“否”:这是不可能解决的。o如果一个可用工件至少有一个“良好”位置,则可能会或可能不会导致解决方案:为了处理这个问题,每个“良好”位置都会生成一个子问题,其中与该放置工件对应的黑色单元格已被删除(即变白),而刚放置的工件类型的可用工件数量减少了一个。基本情况发生在没有黑色单元格的情况下:在这种情况下,我们可以返回YES,因为我们知道可以放置碎片以实现空网格(具体来说,这涉及到根本不放置碎片)

这种递归方法可能会多次重新讨论某些子问题。例如,如果原始网格的一部分包含一个4x2的黑色单元格块,并且您至少有以下两个可用的单元格块:

XX  2         Y  2
              Y
然后,您可以用以下方式填充4x2块

XXYY       YXXY       YYXX
XXYY       YXXY       YYXX
因此产生的子问题(缺少这个4x2块,每种类型的工件少2个)将被解决3次。为了避免这种情况,在某些(相当严格的)情况下,您可以使用自顶向下的动态编程(也称为记忆)。这最多只能解决一次每个子问题,但(可能)需要存储所有可能子问题的答案(每个答案都是一个位,表示是或否),其中有2^(m*n)*(k*u 1+1)*(k*u 2+1)*……*(k*u t+1),其中m和n是网格的宽度和高度,k*u 1,…,k*u t是t