平面上距离最小的所有最接近的点对

时间:2019-11-23 14:01:44

标签: algorithm recursion optimization

我必须从给定集合中找出平面中所有最接近的点对。

我已经成功实现了类似于此伪代码功能的朴素算法O(n²),其中set是输入中所有点的列表,count是输入中所有点的计数,返回dist,这是找到的最小距离,而result是具有该距离的所有点对的列表。

function naive(Points[] set, int count)
    result = []
    distance = INF

    for i=0 to count-1:
        for j=i+1 to count:
           newDistance = distance(set[i], set[j])
           if newDistance < distance:
              result = []
              result.append({set[i], set[j]})
           else if newDistance == distance:
              result.append({set[i], set[j]})

   return (dist, result)

此解决方案效果很好,但是由于O(n²)的复杂性很高,因此对于较大的输入来说非常慢。我想找到一个更快,更优化的解决方案,因此我使用了基于this article的递归分治算法来实现O(n logn)的解决方案,该算法适用于大多数输入,但是由于这种方法确实可以不要遍历像这样的输入失败的所有点(成对的顺序和成对的点的顺序无关紧要):

Input:
{A[0,0], B[1,0], C[1,1] D[0,1]}

Current (wrong) output:
{A[0,0], D[0,1]}, {B[1,0], C[1,1]}

Desired output:
{A[0,0], B[0,1]}, {A[0,0], D[0,1]}, {C[1,1], B[1,0]}, {C[1,1], D[1,0]}

,并且由于它是递归的,因此对于较大的输入,堆栈很容易溢出。解决此问题的更好方法是什么?

谢谢

3 个答案:

答案 0 :(得分:1)

但是您不需要将所有内容与其他所有内容进行比较。对于任何给定的点对,想象它们都位于矩形的[与坐标轴对齐的矩形]对角线上,长度为d

  • 如果斜率为正:
    • x = d行左侧的任何其他点都将更远,因此不应考虑。
    • 位于y = d行下方的任何其他点都将更远,因此不应考虑。
  • 如果斜率为负:
    • x = d行右侧的任何其他点都将更远,因此不应考虑。
    • 位于y = d行下方的任何其他点都将更远,因此不应考虑。

可以想象类似的约束在每种情况下都会为您提供一个边界框,除非您的星座特别密集,否则该边界框应可消除内部循环中要考虑的大部分点。

您肯定需要在这里进行大量的动态编程,以便为大型设备提供合理的运行时间。

答案 1 :(得分:0)

最佳解决方案可能取决于点的分布方式。一种方法是将正方形分割成许多较小的子正方形,并选择每个子正方形平均约有1个点。接下来,将点与相应的子正方形相关联。最后,对于任何给定的点,您只需考虑最近的子正方形即可找到最近的邻居(通过检查所有可能包含较近点的子正方形来确认Nearesr状态)。

答案 2 :(得分:0)

关于第一个问题。我可能会误会,但我可以给您一些提示。

假设您有1000分。将它们按250点分成4组,然后在所有组对中组成500个元素集。总计为6。在这种情况下,任何一对点都将被一半(一对组)覆盖。并且不要忘记保留所有最小值,而不是在每次递归迭代中保留一个最小值。

此外,由于每次划分集时都必须进行分组,因此会增加复杂度,因此您可能会考虑对小集使用“慢速” O(n²)算法,因此实际解决方案将是{ {1}}和O(n log n)

对于第二个问题,我只能提出避免递归的一般方法。如果您有足够的内存,请使用动态编程,即将以前的所有结果保存在内存中并进行遍历,直到用所有可能的参数填充数组为止。因此,您无需进行递归调用,而只是从数组中获取价值。当然,您必须重新开始,直到数组中没有空值为止。实现因任务而异,因此您必须考虑如何实现这一目标。