我有一个整数维矩形平面。在这个平面内部,我有一组非交叉矩形(整数维和整数坐标)。
我的问题是如何才能有效地找到该集的逆;这是平面中未包含在子矩形中的部分。当然,这个点集合形成了一组矩形 - 这些是我感兴趣的。
我当前的天真解决方案使用布尔矩阵(平面的大小),并通过将点i,j设置为0来实现,如果它包含在子矩形中,则为1。然后我遍历矩阵的每个元素,如果它是1(自由),则试图从该点向外“生长”一个矩形。唯一性不是问题(任何合适的矩形都很好)。
有没有哪种算法可以更有效地解决这个问题? (即,无需求助于布尔矩阵。
答案 0 :(得分:7)
是的,这很简单。我以前在SO上回答了一个几乎相同的问题,但还没有找到它。
无论如何,基本上你可以这样做:
可选的最后一步:遍历输出列表,查找可以合并为单个矩形的对的对(即,共享公共边的rects对可以组合成单个rect)。
答案 1 :(得分:5)
好的!第一次实施! (java),基于@Paul's回答:
List<Rectangle> slice(Rectangle r, Rectangle mask)
{
List<Rectangle> rects = new ArrayList();
mask = mask.intersection(r);
if(!mask.isEmpty())
{
rects.add(new Rectangle(r.x, r.y, r.width, mask.y - r.y));
rects.add(new Rectangle(r.x, mask.y + mask.height, r.width, (r.y + r.height) - (mask.y + mask.height)));
rects.add(new Rectangle(r.x, mask.y, mask.x - r.x, mask.height));
rects.add(new Rectangle(mask.x + mask.width, mask.y, (r.x + r.width) - (mask.x + mask.width), mask.height));
for (Iterator<Rectangle> iter = rects.iterator(); iter.hasNext();)
if(iter.next().isEmpty())
iter.remove();
}
else rects.add(r);
return rects;
}
List<Rectangle> inverse(Rectangle base, List<Rectangle> rects)
{
List<Rectangle> outputs = new ArrayList();
outputs.add(base);
for(Rectangle r : rects)
{
List<Rectangle> newOutputs = new ArrayList();
for(Rectangle output : outputs)
{
newOutputs.addAll(slice(output, r));
}
outputs = newOutputs;
}
return outputs;
}
可能是工作示例here
答案 2 :(得分:2)
您应该查看空间填充算法。这些算法是用一些几何图形来填充给定空间的。根据您的需要修改此类算法并不困难。
这种算法是从头开始(空白空间),所以首先用二维平面上已有的方框填充内部数据。然后你让算法完成剩下的工作 - 用另一个框填满剩下的空间。那些盒子正在制作你飞机倒置空间块的清单。
您将这些框保留在某个列表中,然后检查一个点是否在倒置平面上非常容易。您只需遍历列表并检查点是否位于框内。
这是一个site,其中包含大量可能有用的算法。
答案 3 :(得分:0)
我怀疑你可以通过y坐标对矩形进行排序,并采用扫描线方法来获得某个位置。我可能会或可能不会实际构建实现。
答案 4 :(得分:0)
这相对简单,因为你的矩形是不相交的。目标基本上是一组完全覆盖平面的非交叉矩形,一些标记为原始,一些标记为“反向”。
考虑自上而下(或左右或其他)扫描。你有一个当前的“潮汐线”位置。确定您将遇到的下一条水平线的位置是不在潮汐线上的位置。这将为您提供下一个潮汐线的高度。
在这些潮汐线之间,你有一条带,每条垂直线从一条潮线到另一条潮汐线(也许在两个方向上都有)。您可以对这些垂直线的水平位置进行排序,并使用它将条带划分为矩形,并将它们标识为原始矩形(部分)或反向矩形(部分)。
进展到最后,你得到(可能太多太小)的矩形,并且可以选择你想要的那些。您还可以选择(每个步骤)将当前条带中的小矩形与之前的一组潜在可扩展矩形相结合。
即使您的原始矩形可能相交,您也可以这样做,但它更加繁琐。
详细信息留给读者练习; - )