为 N 个单元格的网格找到最佳行和列
Finding optimal rows & columns for grid of N cells
我正在尝试创建一个网格,该网格必须有足够的行和列来容纳 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
。幸运的是,只需一个 non-trivial(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;
}
请注意,我实际上并没有 运行 这段代码,所以如果没有,请将其视为伪代码。
我正在尝试创建一个网格,该网格必须有足够的行和列来容纳 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
。幸运的是,只需一个 non-trivial(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;
}
请注意,我实际上并没有 运行 这段代码,所以如果没有,请将其视为伪代码。