段交叉点

时间:2013-11-12 09:58:59

标签: algorithm computational-geometry

以下是CLRS提出的问题。 圆盘由圆形及其内部组成,由其中心点和半径表示。如果它们有任何共同点,则两个磁盘相交。给出一个O(n lg n)时间算法来确定一组n中的任何两个磁盘是否相交。

这不是我的家庭作业。我想我们可以将每个圆的水平直径作为代表线段。如果两个订单连续出现,那么我们检查两个中心之间的距离长度。如果它小于或等于圆的半径之和,则它们相交。

如果正确的话请告诉我。

3 个答案:

答案 0 :(得分:1)

为磁盘中心构建Voronoi图。这是一个O(n log n)工作。

现在,对于图表的每个边缘,取相应的一对中心并检查它们的盘是否相交。

答案 1 :(得分:0)

  1. 使用圆心建立一个k-d树。
  2. 对于每个圈子(p, r),使用k-d树查找中心距离S 2r更近的圆圈集p
  3. 检查S中的任何圈子是否触及当前圈子。
  4. 我认为这个算法的平均成本是O(NlogN)。

    逻辑是我们遍历集合O(N),并且每个元素都获得O(NlogN)附近的元素子集,因此,先验,复杂度为O(N^2 logN)。但是我们还必须考虑两个随机圆相距小于2r且不接触的概率小于3/4(如果它们接触我们可以使算法短路)。

    这意味着S的平均大小在概率上被限制为较小的值。

答案 2 :(得分:0)

解决问题的另一种方法:

  1. 使用直径为最大圆的网格划分平面。
  2. 使用散列算法对N组中的网格单元进行分类。
  3. 对于每个圆圈,计算它重叠的网格单元格和相应的组。
  4. 获取群组中的所有圈子...
    1. 检查最大的圆圈是否接触到该组中的任何其他圆圈。
    2. 将此算法应用于群组中的其余圈子。
  5. 在scala中实现了相同的算法:https://github.com/salva/simplering/blob/master/touching/src/main/scala/org/vesbot/simplering/touching/Circle.scala