【问题标题】:Random 1-5 5x5 Array随机 1-5 5x5 阵列
【发布时间】:2012-01-10 06:12:07
【问题描述】:

我正在尝试制作一个 5x5 表,其中将随机放入行/列中的数字 1-5。但它们需要为每一行和每一列提供所有不同的数字。

例如: 12345 54123 41532 35214 23451

我目前的代码很长,所以我会给出一个 pastebin 链接。 http://pastebin.com/ex1bcLxh

我们将不胜感激。

【问题讨论】:

  • 仅供参考:你想要的是一个随机的Latin square
  • 几年前我解决了这个看似困难的问题,后来有一个朋友告诉我,这基本上是他在 UVA 的组合数学课上花了一个学期做的事情。总而言之:如果你有时间,自己解决这个问题是非常有益的。

标签: javascript algorithm random combinatorics


【解决方案1】:

有 56 个减少的 Latin squares 订单 5,枚举 here。 “减少”意味着它们中的每一个都具有排序顺序的顶行和最左边的列。

您可以对拉丁方格的行或列应用任何排列, 结果也将是一个拉丁方格。还可以得出,任何拉丁方格都可以通过以下方式转换为简化的拉丁方格:

  1. 排列所有 n 列以将顶行按排序顺序排列
  2. 排列底部 (n-1) 行以将左列置于已排序 订购。

(第一次排列后左上元素已经在正确位置,所以第二步只需要n-1行排序,而不是n行。)

因此,通过反转此操作,我们可以从 56 个缩减的拉丁方格之一开始, 并生成代表完整集合的 56*(5!)*(4!) = 161280 个方格中的任何一个。

所以:

  1. 从 56 个降阶 5 拉丁方格中随机选择一个。
  2. 随机选择底部四行的 4!=24 个排列之一,然后应用它。
  3. 随机选择所有五列的 5!=120 个排列之一,然后应用它。

假设步骤 1-3 中的样本分布均匀,则此过程应从完整的 161280 个 5 阶拉丁方阵中产生均匀分布的样本。

【讨论】:

    【解决方案2】:

    这就是我想到的 - 我没有为优化而烦恼,因为对于问题中提到的 5x5 网格大小,它感觉是瞬时的。 (在 IE7 中测试,即使是 7x7 网格也只需要几秒钟。8x8 明显慢,有时慢到足以触发长时间运行的脚本错误。)

    function createGrid(size) {
       var grid = [],
           row = [],
           x,y,t;
    
       for (x=size; x>0; x--)
          row.push(x);
    
       addRows:
       while (grid.length < size) {
          t = row.slice();
          row = [];
          while (t.length > 0)
             row.push(t.splice(Math.floor(Math.random() * t.length), 1)[0]);
    
          for (y=0; y<grid.length; y++)
             for (x=0; x<size; x++)
                if (row[x] === grid[y][x])
                   continue addRows;
    
          grid.push(row);
       }
    
       return grid;   
    }
    
    var test = createGrid(5);
    alert(test.join("\n"));
    

    如果不是很明显,基本思路是从一行 [5,4,3,2,1] 开始;洗牌并检查是否可以添加;重复直到完成。

    (我考虑从生成所有潜在行开始,然后从它们中随机选择,但这似乎太麻烦了,因为我不太擅长置换算法 - 每次只做随机洗牌似乎少了很多麻烦。)

    【讨论】:

    • 这会给我一个很好的基础,因为我不能让它打印到一个元素上。非常感谢。
    • 用一行代码输出一个非常简单的表格:document.write("&lt;table&gt;&lt;tr&gt;&lt;td&gt;" + createGrid(5).join("&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;").replace(/,/g,"&lt;/td&gt;&lt;td&gt;") + "&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;"); - 当然,你可能不想使用document.write(),确实我不推荐它,但你明白了将函数返回的数组转换为简单表格元素的适当 HTML 是多么容易的想法……尽管在实践中您可能希望使用更文明的东西,例如单独创建 &lt;td&gt; 元素的嵌套 for 循环...
    【解决方案3】:

    一般来说,这是一项艰巨的任务,特别是如果您担心在所有拉丁方格中均匀分布。 (至少有 one book 完全致力于这个主题。)这是一种算法的伪代码(不是最有效的,但可以完成工作):

    for each row {
       make an array of the integers 1..N
       repeat {
           make a random permutation of the array
       } while (array conficts with any previously assigned row)
       set row to array
    }
    

    (Array a "conflicts" with row r if a[i] == r[i] for some i in the row.) 这假设您有代码来随机打乱数组。如果您手边没有随机播放算法,请在网上搜索。

    【讨论】:

      【解决方案4】:

      正如Ted Hopp 所指出的,这也称为Latin Square

      拉丁方格是exact cover 问题的一类,因此可以使用Knuth's Algorithm X 找到解决方案。

      Dancing Links 表示在 Javascript 中编码应该不会太难。我在 Lua 中实现了类似的东西。

      术语可能令人困惑,因为算法描述指的是“矩阵”、“行”和“列”,但这些与(输出)矩阵的行和列不同。相反,“行”是数组中的候选条目(a[1][2]=3 等),“列”是其中一个坐标或值是通配符的模式,例如a[Y][2]=3, a[1][X]=3, a[1][2]=V.

      要选择随机解决方案,您可以随机打乱条目列表,然后再将它们分配给算法的“行”。 (在 Dancing Links 表示的情况下,行形成一个循环链表,您可以将条目以随机顺序插入到此列表中。)

      【讨论】:

        猜你喜欢
        • 2019-07-26
        • 2022-08-08
        • 2017-08-26
        • 2017-03-18
        • 1970-01-01
        • 1970-01-01
        • 2012-01-01
        • 1970-01-01
        • 2010-09-13
        相关资源
        最近更新 更多