有一层砖砌,测量 N 乘 M 个单元。一块砖正好占据两个相邻的单元格。需要计算在下一层砌体中放置砖块的选项之一。
限制:新层的砖块不能与上一层砖块的位置完全重合。
输入是一个 NxM 矩阵,表示一个砌体层,其中填充有从 1 到 NxM/2 的数字对,其中每对数字代表一块砖。
样本输入和样本响应:
那些。在输入矩阵处:
{
{ 1, 1, 2, 2, 3, 3, 4, 4 },
{ 5, 5, 6, 6, 7, 7, 8, 8 },
{ 9, 9, 10, 10, 11, 11, 12, 12 },
{ 13, 13, 14, 14, 15, 15, 16, 16 },
}
在出口处:
{
{ 1, 2, 3, 4, 5, 6, 7, 8 },
{ 1, 2, 3, 4, 5, 6, 7, 8 },
{ 9, 10, 11, 12, 13, 14, 15, 16 },
{ 9, 10, 11, 12, 13, 14, 15, 16 },
}
检查层正确性的测试方法:
public bool CheckLayers(int n, int m, int[,] current, int[,] previous)
{
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
if (i < n - 1
&& current[i, j] == current[i + 1, j]
&& previous[i, j] == previous[i + 1, j]) return false;
if (j < m - 1
&& current[i, j] == current[i, j + 1]
&& previous[i, j] == previous[i, j + 1]) return false;
}
}
return true;
}
因此,让我们考虑砌体层的 2x2 单元的所有可能部分:
如您所见,对于 2x2 单元的任何部分,总是可以拿起几块砖安装在下一层:即 如果在该区域中,其中一个砖块是“水平”放置的(实际上整个层是水平的,但为了便于指定,我将其垂直放置),那么我们取一对“垂直”砖块,否则我们取一对“水平”的。在图片中,我用红色矩形表示了下一层可能放置的砖块。请注意,如果在选定的 2x2 区域中,所有单元格都被“一半”占据,即 没有一整块砖,那么下一层的几块砖可以垂直和水平放置,即 上述算法也适用于这种情况。
因此,如果输入值 N 和 M 都是偶数,那么砌体层可以划分为 2x2 单元的部分,并根据上述算法进行填充。对于偶数 N 和 M,解总是存在并且是微不足道的。
现在,考虑 N 或 M 为奇数的情况。需要注意的是,如果 N 和 M 同时都是奇数,那么我们不能用整数个砖块来平铺层,即 不可能有这样的输入数据,我们不考虑这种情况。
因此,砌体层的尺寸之一是奇数。考虑“宽度”M 为奇数的情况,如果“高度”N 为奇数,那么我们总是可以转置输入数据并使用相同的算法。
让我们将砌体“划分”成 2 个单元格高的“水平”条纹(高度是均匀的,所以这是可能的),并独立考虑每个条纹。对于这样的条带,我们必须至少垂直放置一个积木,并且这块积木必须在 0、2、4、...、(M-3) 或 (M-1) 垂直(如果我们有垂直砖位于具有奇数索引的垂直,那么在垂直中将至少有一个(偶数两个)具有偶数索引的垂直砖,我们将考虑它)。值得注意的是,垂直砖的左右两侧会有偶数个垂直。
那些。对于每个高度为 2 个单元格的水平条,我们查看具有偶数索引的垂直线,如果其中一个垂直线没有垂直砖,那么我们在下一层放置一个垂直砖,并填充左侧区域根据偶数 N 和 M 的算法,它的右边。如果在条带 2xM 中所有偶数垂直都被垂直砖占据,那么没有解决方案。
我无法证明算法的正确性,但我没有设法找到输入数据的反驳示例。
剩下的只是将这个算法翻译成代码。
C# 中的幼稚实现:
使用示例:
可以更短