找到未被一组矩形触摸的点的高效算法

时间:2010-10-04 20:51:16

标签: algorithm language-agnostic

输入:区域(0,0)到(1600,1200)内的一组矩形。

输出:没有任何矩形包含的点。

什么是有效的算法?我目前唯一能想到的两个是:

  • 创建一个1600x1200的布尔数组。遍历每个矩形的区域,将这些位标记为True。在最后迭代并找到一个错误的位。问题是它浪费了内存并且可能很慢。
  • 通过积分随机迭代。对于每个点,迭代矩形并查看它们中是否包含该点。返回没有矩形包含的第一个点。问题是人口稠密的问题实例真的很慢。

为什么我这样做?这不是用于家庭作业或编程比赛,虽然我认为这个问题的一个更复杂的版本被问到一个(每个矩形都有一个'颜色',你必须输出他们给你的几个点的颜色)。我只是试图以编程方式在Windows上禁用第二台显示器,而我遇到了更多sane approach的问题。所以我的目标是在桌面上找到一个未占用的位置,然后模拟右键单击,然后模拟从显示属性窗口禁用它所需的所有点击。

8 个答案:

答案 0 :(得分:4)

对于每个矩形,创建沿水平方向的运行列表。例如,一个100x50的矩形将生成50次100次运行。用最左边的X坐标和Y坐标将它们写入列表或地图。

对列表进行排序,首先是Y,然后是X.

浏览列表。重叠运行应该是相邻的,因此您可以合并它们。

当你发现第一次没有在整个屏幕上延伸时,你已经完成了。

答案 1 :(得分:3)

  • 我会用我最喜欢的图形库分配一个图像,让它做矩形绘图。
  • 您可以先尝试低分辨率版本(缩小8倍),如果至少有15x15区域,则可以使用。如果失败,你可以尝试高分辨率。
  • 在.net中使用Windows HRGN(Region)。它们是为此而发明的。但这不是语言无关的。
  • 最后你可以做矩形减法。唯一的问题是,每次从另一个矩形中减去一个矩形时,最多可以获得4个矩形。如果有很多小的,这可能会失控。

P.S。:考虑针对最大化窗口进行优化。然后你就可以看出没有命中测试就没有像素可见。

答案 2 :(得分:3)

  • 对所有X坐标(矩形的开头和结尾)进行排序,再加上0&amp; 1600,删除重复。表示该Xi(0 <= i <= n)。
  • 对所有Y坐标(矩形的起点和终点)进行排序,再加上0&amp; 1200,删除重复项。表示该Yj(0 <= j <= m)。
  • 使用前面的点给定的Xi和Yj制作一个n * m网格,这应该比原来的1600x1200小得多(除非你有一千个矩形,在这种情况下这个想法不适用)。此网格中的每个点都映射到原始1600 x 1200图像中的矩形。
  • 在此网格中绘制矩形:从第一步中找到集合中矩形的坐标,在网格中绘制。每个矩形将在窗体上(Xi1,Yj1,Xi2,Yj2),因此您在小网格中绘制所有点(x,y),使得i1&lt; = x&lt; i2&amp;&amp; j1&lt; = y&lt; J2。
  • 找到网格中第一个未上漆的单元格,从中取任意点,例如中心。

注意:假设矩形在形式上:(x1,y1,x2,y2),表示所有点(x,y),使得x1 <= x&lt; x2&amp;&amp; y1&lt; = y&lt; Y2

Nore2:Xi&amp; Yj可以存储在排序的数组或树中以进行O(log n)访问。如果矩形的数量很大。

答案 3 :(得分:1)

如果您知道矩形的最小x和y尺寸,则可以使用较少的像素来使用第一种方法(布尔数组的2D数组)。

考虑到1600x1200小于2M像素。真的那么多记忆吗?如果你使用位向量,你只需要235k。

答案 4 :(得分:1)

你的第一个想法并不是那么糟糕......你应该只改变数据的表示。 你可能会对布尔的稀疏数组感兴趣。

依赖于语言的解决方案是使用Area (Java)

答案 5 :(得分:1)

如果我必须自己这样做,我可能会选择2d阵列的布尔值(特别是按照jdv建议缩小,或使用加速图形例程)或随机点方法。

如果你真的想做一个更聪明的方法,你可以考虑矩形。从带有角(0,0),(1600,1200)=(lx,ly),(rx,ry)的矩形开始,并“减去”第一个窗口(wx1,wy1)(wx2,wy2)。

如果它完全包含在原始的自由矩形内,则最多可以生成4个新的“仍然可用”矩形:(例如,新窗口的所有4个角都包含在旧窗口中)它们是(lx,ly) - (rx,wy1),(lx,wy1) - (wx1,wy2),(wx2,wy1) - (rx,wy2)和(lx,wy2) - (rx,ry)。如果窗口的一个角落重叠(只有一个角落在自由矩形内),它会将其分成两个新的矩形;如果一侧(2个角)伸入其中则将其分成3个;如果没有重叠,没有任何改变。 (如果它们都是轴对齐的,则内部不能有3个角。)

然后继续循环浏览窗口,测试交集和子划分矩形,直到你有一个矩形方面的所有剩余可用空间的列表(如果有的话)。

这可能会比上面的任何图形库驱动的方法慢,但写起来会更有趣:)

答案 6 :(得分:1)

  • 保留一个代表未覆盖空间的矩形列表。将其初始化为整个区域。
  • 对于每个给定的矩形
    • 对于未覆盖空间中的每个矩形
      • 如果它们相交,则将未覆盖的空间划分为覆盖矩形周围的较小矩形,并将较小的矩形(如果有)添加到未覆盖的矩形列表中。
  • 如果您的未覆盖空间列表仍有任何条目,则它们包含给定矩形未涵盖的所有点。

这不取决于您所在区域的像素数,因此适用于大(或无限)分辨率。未覆盖列表中的每个新矩形将在其他矩形对的唯一交叉点处具有角,因此列表中最多将有O(n ^ 2),总运行时间为O(n ^ 3)。您可以通过将未覆盖的矩形列表保持为更好的结构来检查每个覆盖矩形,从而提高效率。

答案 7 :(得分:0)

这是一个仅1600 + 1200空间复杂度的简单解决方案,它在概念上类似于创建1600x1200矩阵但不使用整个矩阵:

  1. 从两个布尔数组W [1600]开始,H [1200]设置为true。
  2. 然后对于坐标范围为w1..w2和h1..h2的每个可见窗口矩形,将W [w1..w2]和H [h1..h2]标记为false。
  3. 要检查坐标(w,h)的点是否落在空白区域,请检查 (W [w]&amp;&amp; H [h])== true