为N个单元格找到最佳行和列

问题描述

我正在尝试创建一个网格,该网格必须具有足够的行和列才能容纳length个单元格。以下是一些示例:

- Length: 8: 2 rows x 4 cols
- Length: 9: 3 rows x 3 cols
- Length: 10: 5 rows x 2 cols
- Length: 11: 4 rows x 3 cols (with one extra)

我想出了一个使用平方根的解决方案,它给了我一个非常接近的解决方案:

var cols = Math.ceil(Math.sqrt(length));
var rows = Math.ceil(length / cols);

可以有多余的单元格(例如质数),但是我希望尽可能地减少它们。这种方法的问题是,当有更好的解决方案时,我会得到空单元格:

- Length: 8: returns 3 x 3,but 2 x 4 has 0 remainders
- Length: 10: returns 4 x 3,but 5 x 2 has 0 remainders
- Length: 15: returns 4 x 4,but 5 x 3 has 0 remainders

是否有另一种方法来优化我的网格,以尽可能减少额外的单元格数量?我觉得我的尝试并不理想。

解决方法

对于偶数m,我们可以轻松地说:

cols = m / 2
rows = 2

对于奇数长度m,我们需要分解m。幸运的是,只需一个非平凡(1或m)因素就足够了。通过以下算法:

for(var i = 3; i * i < m; i += 2){
    if(m % i == 0)
        return i;
}
return -1;

如果结果为-1,它将是质数,因此,最终重用将是:

cols = (m+1)/2
rows = 2

否则,如果我们将因子称为k,结果将是:

cols = m / k
row = k

您可以在以下位置找到最终结果:

function factor(m){
   // if m is even
   if(m % 2 == 0)
       return [2,m/2]   
   for(var i = 3; i * i < m; i += 2){
        // m is odd and not prim
        if(m % i == 0)
            return [i,m/i];
   }
   // m is odd prime
   return [2,(m+1)/2];
} 

console.log(factor(8));
console.log(factor(10));
console.log(factor(11));
console.log(factor(15));

此功能的结果已优化(根据您的定义)。因为对于非质数,余数为零,对于质数为1

,

假设这些数字从未达到天文数字,您只需检查每个数字从平方根开始的拟合度如何,并在考虑到余数和缺乏平方度的评估功能的情况下,跟踪最佳数字。像这样:

function optimizeRectangle(N) {
  let bestRectangle = null;
  let best_evaluation = Infinity;

  let start_row = Math.floor(Math.sqrt(N));
  // Maximum aspect ratio of 3:1
  for (let offset = 0; offset < start_row / 2; offset++) {
    let row = start_row - offset;
    let col = Math.ceil(N/row);
    let remainder = row * col - N;
    let evaluation = remainder + offset; // or some other function of remainder and offset
    if (evaluation < best_evaluation) {
      best_evaluation = evaluation;
      best_rectangle = [row,col];
    }
  }
  return best_rectangle;
}

请注意,我实际上并未运行此代码,因此如果没有运行,请将其视为伪代码。