寻找(不完全)拉丁方

时间:2015-06-04 08:32:33

标签: algorithm permutation cycle-detection

给定一个大小为m X n的矩阵,行或列中没有重复值,是否有一种检测周期的有效方法?

例如,这是一个样本矩阵:

  

3 5 2 9 7 4
   4 3 6 1 8 7
   1 4 7 5 2 9
   9 8 3 2 6 1
   2 6 8 7 3 5

至少有一个大小为3的排列周期:

  

3 5 2 9 7 4
     4 8 3 1 6 7
     1 4 7 5 2 9
     9 6 8 2 3 1      2 3 6 7 8 5

第2,4和5行中的值3,6和8形成一个循环。

问题与Kakuro谜题有关。与解决它们无关,而是试图检测特定网格的任何布局是否使其不合适。任何类型的循环都会使该特定布局无效 - 因为两个布局的行和列的总和是相同的。

1 个答案:

答案 0 :(得分:0)

我认为你可以在O(n ^ 3)时间内为n x n网格做到这一点。

<强>观

考虑你的示例网格,并假设topleft 3和5是否可以以拉丁子方格结束。

(3) (5)  2   9   7   4
 4   8   3   1   6   7
 1   4   7   5   2   9
 9   6   8   2   3   1
 2   3   6   7   8   5

因为我们想要一个拉丁方,我们被迫在(5)列中包含3(所有值必须出现在每列中),以及附近的2(必须形成正方形):

(3) (5)  2   9   7   4
 4   8   3   1   6   7
 1   4   7   5   2   9
 9   6   8   2   3   1
(2) (3)  6   7   8   5

我们可以继续这样做一段时间,但我们很快就会遇到一个问题:左边的行不包含5.包括左上角3和左上角5导致矛盾。

通常,只要我们在同一行或同一列中包含2个值,该对就会强制包含最多4个其他值和/或意味着矛盾。我们想要使用这种暗示结构来快速消除不良解决方案,只留下好的解决方案。

制作图表

由于我们有这种有用的蕴涵结构,我们应该探索它。为每个水平和垂直值对创建一个节点,并且只要一对意味着必须包含另一对,就在这些节点之间插入有向边。还有一个节点&#34;矛盾&#34;。例如,与示例中左上角{(0, 0), (0, 1)}对应的(3) (5)对将具有{(0, 0), (4, 0)}{(0, 1), (4, 1)}contradiction的传出边。

结果是一个图表,其中有许多节点指向矛盾,并且可能有一些节点在一个周期中指向彼此。撕掉矛盾节点和任何直接或间接指向它的东西,剩下的所有东西应该是循环,任何循环都应该对应一个拉丁方。

<强>正确性

老实说,我不确定这是否正确。很明显拉丁方是立即彻底检查每个添加对的意义上的正确性导致所有必要的工作发生...但我认为所有的坏情况,将遗漏的是价值重复且保证不会在输入中发生的那些。

需要做更多的工作。

<强>复杂性

图中有O(n ^ 3)个节点,因为行或列中有O(n ^ 2)对,O(n)行+列。还有O(n ^ 3)个边,因为每个节点最多有4个外边。

如果您正在使用边缘列表,则删除指向contradiction的内容需要与节点数成比例的时间。只需沿着上游边缘进行向后洪水填充。

检测循环需要与节点和边缘数量成比例的时间:桶节点基于它们拥有的节点数(最多4个),并继续删除0输出桶中的节点并重新分组受影响的节点直到完成如果剩下任何东西,那就是一个循环。

由于所有操作都需要与节点和边缘数量成比例的时间,并且我们有O(n ^ 3)个节点+边缘,因此整个算法需要O(n ^ 3)时间。