我认为你可以在n x n的网格中用O(n^3)的时间完成此操作。
思路:
考虑你的示例网格,并假设左上角的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个其他值,并/或意味着存在矛盾。我们想利用这种暗示结构,快速消除不良解决方案,只留下好的解决方案。
创建一个节点,表示每个水平和垂直值对,并在这些节点之间插入有向边,每当一对暗示另一对必须被包含。还要有一个表示“矛盾”的节点。例如,在示例中,与左上角(3)(5)相对应的{(0,0),(0,1)}对将向{(0,0),(4,0)}、{(0,1),(4,1)}和“矛盾”发出出边。
结果是一个图,有很多节点指向矛盾,并且可能有一些节点在一个循环中相互指向。删除矛盾节点及其直接或间接指向的所有内容,剩下的应该只有循环和任何循环都应该对应于拉丁方阵。
正确性
老实说,我不确定这是否正确。显然,拉丁方阵没有立即被全面检查其正确性,也就是说,每个添加的对都会引起必要的工作...但我认为所有被忽略的坏情况都是那些在输入中保证不会发生值重复的情况。
需要更多的工作。
复杂度
图中有O(n^3)个节点,因为一行或一列中有O(n^2)对,而行+列有O(n)个。边也有O(n^3),因为每个节点最多有4个出边。
删除指向“矛盾”的东西需要与节点数量成比例的时间,假设您正在使用边缘列表。只需进行反向洪泛填充,沿着上游的入边进行跟踪。
检测循环所需的时间与节点和边的数量成比例:基于它们的出度节点数(最多4个),将节点放入桶中,并删除0出度桶中的节点并重新将受影响的节点放入桶中,直到完成。如果还有剩余节点,则存在循环。
由于所有操作的时间与节点和边的数量成比例,而我们具有O(n ^ 3)个节点+边,因此整个算法需要O(n ^ 3)时间。