问题表明我有一个大矩形,尺寸为L和W,以及无限数量的相同小矩形,尺寸为l和w。 L * W保证大于l * w。所以我想找出可以放入大矩形的小矩形的最大数量,而不会重叠。您可以将小矩形放在您喜欢的任何方向。
答案 0 :(得分:1)
矩形在平铺时最适合,两者之间没有空隙。所以,概述了如何做到这一点:
首先,如果你只是将它们平铺在一起,弄清楚有多少适合:
lFit = L / l // integer division for these, no remainder
wFit = W / w
你知道如果你把它们放在与大矩形相同的方向上,你可以在里面放置lFit * wFit
个矩形。再次检查其他方向,并选择较大的方向作为基础。
现在你可能还剩下一些空间。那个空间由矩形组成。您可以从上一步轻松找到这些大小。再次为这些较小的矩形运行它并添加到基数。递归直到不再适合。
如果没有任何瓷砖适合“剩余的”较小的矩形,则需要检查倾斜的矩形。
一旦您的瓷砖不适合轴对齐到矩形中,您需要倾斜它。您可以通过倾斜它们 来包装最多的瓷砖,以适应最长的盒子尺寸,并将其牢固地放在三个墙壁上。然后你尝试在它下面堆叠更多。
注意:对于这里的所有数学,我使用width
作为“最长边”。如果你的矩形/瓷砖不匹配,只需翻转尺寸。
要确定正确的旋转角度,您可以使用试验/错误二进制搜索。我确信有一种更“肮脏”的方式来做,但这种方法效果很好。旋转矩形的边界宽度的公式是(以弧度表示的角度):
width = w * cos(angle) + h * sin(angle)
要进行试验/错误,只需将其循环直至达到容差:
// boxWidth, tileWidth, tileHeight
public static double getAngle(double bw, double tw, double th){
double err = 10;
double maxAngle = PI * 0.25; // 45 degrees, any more would be taller than wide
double angle = maxAngle * 0.5; // start in the middle
double angleDelta = angle * 0.5; // amount to change;
count = 0;
while(count++ < 100){
double rotatedWidth = tw * Math.cos(angle) + th * Math.sin(angle);
err = rotatedWidth - bw;
if(Math.abs(err) < TOLERANCE){
return angle;
} else if(err < 0){
angle -= angleDelta;
} else {
angle += angleDelta;
}
angleDelta *= 0.5;
}
return -1; // found no good angle in 100 attempts
}
一旦你有角度,你可以使用基本触发来找出其他一些点:
y1
y1 = sin(angle) * tileWidth
y2
y2 = sin((PI * 0.5) - radians) * tileHeight
y2
个垂直空间,因此适合的数字为:
(boxHeight - y1) / y2
我创建了一个你可以玩的小ideone.com example。代码相当丑陋,但它的工作原理。对于您在评论中的示例(13x8, 14x1
),它会显示:
Rotated 26.23397827148437 degrees
y1 = 6.188525444904378
y2 = 0.8969959689614577
numTiles = 2