生成对角拉丁方阵的算法

时间:2015-10-11 12:48:18

标签: algorithm math matrix

我需要给定N创建N * N矩阵,其在行,单元格,次要和主要对角线中没有重复,并且值为1,2,3,....,N。

对于N = 4,其中一个矩阵如下:

 1 2 3 4 
 3 4 1 2 
 4 3 2 1
 2 1 4 3

3 个答案:

答案 0 :(得分:3)

问题概述

您描述的数学结构是 对角拉丁方 。构造它们是比算法或程序化更多的数学问题。

要正确理解它是什么以及如何创建,请阅读以下文章:

  1. Latin squares definition

  2. Magic squares definition

  3. Diagonal Latin square construction< - p.2通过证据和其他有趣的属性回答您的问题

  4. 简短回答

    构建 对角线拉丁方 的可能方法之一:

    N 是所需矩阵 L 的幂。

    如果,则存在来自范围[0; N-1]且满足属性的 A B 的数字:

    • A 相对论素数 N

    • B 相对来自 N

    • (A + B)相对来自 N

    • (A - B)相对来自 N

    然后您可以使用以下规则创建所需的矩阵:

    L[i][j] = (A * i + B * j) mod N
    

答案 1 :(得分:1)

这是N <= 9:(python)

的快速方法
import random


def generate(n):
    a = [[0] * n for _ in range(n)]

    def rec(i, j):
        if i == n-1 and j == n:
            return True
        if j == n:
            return rec(i+1, 0)
        candidate = set(range(1, n+1))
        for k in range(i):
            candidate.discard(a[k][j])
        for k in range(j):
            candidate.discard(a[i][k])
        if i == j:
            for k in range(i):
                candidate.discard(a[k][k])
        if i+j == n-1:
            for k in range(i):
                candidate.discard(a[k][n-1-k])
        candidate_list = list(candidate)
        random.shuffle(candidate_list)
        for e in candidate_list:
            a[i][j] = e
            if rec(i, j+1):
                return True
            a[i][j] = 0
        return False

    rec(0, 0)
    return a

for row in generate(9):
    print(row)

输出:

[8, 5, 4, 7, 1, 6, 2, 9, 3]
[2, 7, 5, 8, 4, 1, 3, 6, 9]
[9, 1, 2, 3, 6, 4, 8, 7, 5]
[3, 9, 7, 6, 2, 5, 1, 4, 8]
[5, 8, 3, 1, 9, 7, 6, 2, 4]
[4, 6, 9, 2, 8, 3, 5, 1, 7]
[6, 3, 1, 5, 7, 9, 4, 8, 2]
[1, 4, 8, 9, 3, 2, 7, 5, 6]
[7, 2, 6, 4, 5, 8, 9, 3, 1]

答案 2 :(得分:1)

以数学方式做这件事会很好,但我会提出我能想到的最简单的算法 - 蛮力。

处于高水平

  • 我们可以将矩阵表示为数组数组
  • 对于给定的N,构造S一组数组,其中包含[1..N]的每个组合。这些将会N!
  • 使用递归&amp;迭代选择过程(例如搜索树),搜索这些数组的所有顺序,直到其中一个“唯一性”规则被破坏

例如,在您的N = 4问题中,我会构建

S = [
[1,2,3,4], [1,2,4,3]
[1,3,2,4], [1,3,4,2]
[1,4,2,3], [1,4,3,2]
[2,1,3,4], [2,1,4,3]
[2,3,1,4], [2,3,4,1]
[2,4,1,3], [2,4,3,1]
[3,1,2,4], [3,1,4,2]
// etc
]

R = new int[4][4]

然后算法类似于

  1. 如果R'已满',则表示已完成
  2. 评估S中的下一行是否适合R,
    • 如果是,请将其插入R,重置S上的迭代器,然后转到1.
    • 如果不是,则在S
    • 上增加迭代器
  3. 如果要在S中检查更多行,请转到2。
    • 否则你在S中迭代并且没有任何行适合,所以删除添加到R的最新行并转到1.换句话说,探索另一个分支。
  4. 为了提高该算法的效率,实现更好的数据结构。而不是所有组合的平面数组,使用某种前缀树/ Trie来减少“选项”的存储大小并减少每次迭代中的搜索区域。