【问题标题】:Creating a Latin Square program in Python在 Python 中创建拉丁方程序
【发布时间】:2014-09-22 23:45:38
【问题描述】:
order = input("Input the order of a Latin Square: ")
top_left = input("Input the top-left number: ")
int_order = int(order)
int_top_left = int(top_left)
for order in range(int_order):
    for top_left in range(int_order):
        print(int_top_left, end=" ")
    print()

我正在尝试输入一个订单,然后输入一个左上角的金额,并让它从那里创建一个拉丁方块。问题是,我不知道如何让它在行和列中计数。该程序仅将左上角的数字排列在一个正方形网格中,大小顺序为 x 顺序。

【问题讨论】:

  • 您到底希望您的代码做什么?用户输入左上角的数字(您可能应该检查它是否在 1..order 范围内),它应该打印出填充的拉丁方格?

标签: python latin-square


【解决方案1】:

关键思想是您可以创建一个有效行并旋转该行以生成一个有效正方形:

def create_latin_square(n: int):
    row = [i for i in range(1, n+1)]
    return [row[i:] + row[:i] for i in range(n)]

一个大小为 4 的正方形看起来像这样:

[1, 2, 3, 4]  # row
[2, 3, 4, 1]  # row, rotated by 1 to the left
[3, 4, 1, 2]  # row, rotated by 2 to the left
[4, 1, 2, 3]  # row, rotated by 3 to the left

然后只旋转第一行:

def create_latin_square(n: int, start_el: int=1):
    row = [i for i in range(1, n+1)]
    row = row[start_el-1:] + row[:start_el-1]
    return [row[i:] + row[:i] for i in range(n)]

【讨论】:

    【解决方案2】:

    拉丁方是一个 NP 完全问题(参见 http://en.wikipedia.org/wiki/Latin_square#Mathematical_puzzles),就像数独一样,只是去掉了一些约束。

    您需要(以某种方式)搜索给定顺序的拉丁方格的空间。您有几种可能:

    1。手动状态空间搜索

    您可以使用一些状态空间搜索技术自己编写拉丁方解算器。您的初始状态将是拉丁方格,除了左上角以外的所有字段都为空白。您可以一次查看一个字段并尝试将其设置为满足约束的数字。如果存在,则继续下一个字段,否则返回父状态。

    您可以在在线状态空间搜索中找到大量资源。搜索关键字,如:回溯、DFS、BFS、分支定界、A*

    2。转换为另一个组合问题并使用现有的求解器

    您可以将此问题转换为另一个经过充分探索的组合优化问题,并为该问题使用求解器。

    这个问题可以表示为图形着色 - 您可以通过以下方式将其转换为图形着色问题:

    1. 方块中的每个字段是图中的一个节点,方块中的每个数字是一种颜色。
    2. 如果两个节点在同一行或同一列中,则它们之间存在一条边。
    3. 着色解决后,用数字替换颜色。

    事实上,拉丁方(或多或少)图形着色,只是使用不同的术语:)。

    图形着色可以通过 CSP(约束满足编程)求解器来解决,或者您可以将问题直接插入 CSP。

    您可以使用 ILP(整数线性规划)来解决它。有为此调整的求解器。 GLPK 是一个开源的,它有 python 绑定(例如PyGLPK

    3。使用元启发式方法

    如果您想出一种方法来表达由某些数字填充的某些正方形的错误(例如,违反约束的数量,即同一行或列中相同数字对的数量),您可以使用一些随机像 Simmulated AnnealingEvolutionary Algorithms 这样的元启发式算法,可以使用该错误函数将解决方案推向有效的解决方案。

    【讨论】:

    • “拉丁方是一个 NP 完全问题”——并非总是如此。特别是如果我的解决方案显示只有一个单元格被填充。
    • 这里的问题是拉丁方构造,而不是拉丁方完成,所以它不是NP完全的。除了回溯之外,所有这些方法都大材小用。
    【解决方案3】:

    您可以使用 Jacobson 和 P. Matthews 方法。

    M. T. Jacobson 和 P. Matthews,生成均匀分布 随机拉丁方格,J. Combinatorial Design 4 (1996), 405-437

    参加look

    【讨论】:

      【解决方案4】:

      这个呢?

      def latin_square(n, mod='ballanced'):
        import numpy as np
      
        mat = np.empty((n,n,))*np.nan
      
        mat[:,0] = range(1,n+1)
      
        if mod=='ballanced':
          shift = (.5-np.mod(np.array(range(1,n)),2))/.5*np.ceil(np.array(range(1,n))/2)
          shift = shift.astype(int)
        elif mod=='normal':
          shift = np.array(range(n-1, -1, -1))
      
        for col in range(1, n):
          mat[:, col] = np.roll(mat[:,0], shift[col-1])
          
        return(mat)
      
      
      latin_square(6)
      
      array([[1., 2., 6., 3., 5., 4.],
         [2., 3., 1., 4., 6., 5.],
         [3., 4., 2., 5., 1., 6.],
         [4., 5., 3., 6., 2., 1.],
         [5., 6., 4., 1., 3., 2.],
         [6., 1., 5., 2., 4., 3.]])
      

      【讨论】:

        【解决方案5】:
        # Highest number in square
        order_of_sq = int(input("Enter order of sq: "))
        
        # Number you want to start the square with
        top_left = int(input("Enter top left number: "))
        
        # Sets a placeholder for a variable called top_left_init
        top_left_init = 0
        
        # Sets the initial value of top_left to a new variable because the code will
        # change the value of top left later on
        top_left_init += top_left
        
        # Initialize the value of count
        count = 0
        
        # Add 1 to the highest value in latin square to account for the range function
        # (the ending number is always one less than the number you enter into the
        # range function)
        for values in range(1, order_of_sq + 1):
        
            # Prevents the program from adding too many characters to the line
            while count != order_of_sq:
        
                # Prints numbers with spaces after them in a horizontal manner
                print(top_left, sep=" ", end=" ")
        
                # Adds 1 to the top_left
                top_left += 1
        
                # Count is used to keep track of how many characters are in your line
                count += 1
        
                # Restarts the numbers in your line when you reach the highest number
                if top_left == order_of_sq + 1:
                    top_left = 1
        
            # Creates a new row
            print()
            count = 0
        
            # Calls the initial value of top_left and adds 1 to it before beginning the
            # next row
            top_left_init += 1
        
            # Resets top_left_init to 1 if it reaches the highest number in the square
            if top_left_init == order_of_sq + 1:
                top_left_init = 1
                top_left = top_left_init
            else:
                top_left = top_left_init
        

        【讨论】:

        • 这应该包括代码的解释,所有的代码答案都没有价值。
        • @TristanWiley:我正要问“但是 cmets 呢?”当我意识到它们并没有那么多的补充时。尽管如此,代码确实有一个内置的解释,只是没有关注最有趣的部分。
        • cmets 旨在帮助他/她从头到尾遵循程序。学生可以轻松地使用 Google 拉丁方来更深入地理解这个概念。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多