直线上最近的一对点
Posted
技术标签:
【中文标题】直线上最近的一对点【英文标题】:Closest pair of points across a line 【发布时间】:2013-09-07 22:29:53 【问题描述】:我有两组 2D 点,它们在平面上被一条线分开。我想有效地找到一对点,由每组中的一个点组成,它们之间的距离最小。 Radu Litiu 有一篇看起来非常方便的论文,两个分离点集的最近对,但它使用 L1(曼哈顿)距离度量而不是欧几里得距离。
有人知道适用于欧几里得距离的类似算法吗?
我几乎可以看到标准分治最近对算法的扩展——将这两个集合除以垂直于原始分割线的中线,在两侧递归,然后寻找一个更接近的对距离中位数的每一侧一个点。如果与递归步骤的最小距离为 d,则中值一侧的点的伴星必须位于尺寸为 2d*d 的框内。但与原始算法不同的是,我看不到任何方法来限制该框内的点数,因此整个算法就变成了 O(m*n)。
有什么想法吗?
【问题讨论】:
我们在谈论多少分? N 个。 :-) 在这种情况下,一个简单的 m*n 蛮力扫描可能会具有最佳的挂钟性能,但从更理论的角度来看,我也对这个问题感兴趣。 【参考方案1】:Evgeny's answer 可以工作,但如果没有库支持,需要付出很多努力:计算完整的 Voronoi 图以及额外的扫描线算法。更容易依次枚举两组点的 Voronoi 单元格与分隔线相交的点,然后通过线性时间合并步骤测试单元格相交的所有点对。
要计算所需的 Voronoi 图片段,假设 x 轴是分隔线。按 x 坐标对集合中的点进行排序,丢弃 y 大于其他具有相同 x 的点的点。开始按 x 坐标顺序扫描这些点,将它们压入堆栈。在推送之间,如果堆栈至少有三个点,例如 p、q、r,其中 r 最近被推送,则测试平分 pq 的线是否与平分 qr 的线之后的分隔线相交。如果是这样,丢弃 q,并用新的前三名重复测试。粗略的 ASCII 艺术:
Case 1: retain q
------1-2-------------- separating line
/ |
p / |
\ |
q-------r
Case 2: discard q
--2---1---------------- separating line
\ /
p X r
\ /
q
【讨论】:
呵呵,那就更好了。如果这些点是预先排序的 WRT 分隔线(它们实际上可能是,我需要检查),看起来这会将算法降低到线性时间。非常好!【参考方案2】:对于一组中的每个点,在另一组中找到最近的点。这样做时,只保留一对点之间的距离最小。这将给定问题减少到另一个问题:"Algorithm to find for all points in set A the nearest neighbor in set B",这可以使用扫描线算法解决(1)一组点和(2)其他组的 Voronoi 图。
算法复杂度为 O((M+N) log M)。而且这个算法没有利用两组点被一条线隔开的事实。
【讨论】:
啊,聪明。所以先构建 Voronoi 图,然后进行扫描,扫描用于将点与 Voronoi 区域相关联,而不需要对每个点进行单独的最近邻搜索。很好的答案!【参考方案3】:这个怎么样:
判断任意一点在哪一边:
让 P 成为您的点 (P0,...Pi,...Pn) 设A,B为分隔线起点 所以:side(Pi) = ((B-A).(Pi-A)) 的符号 这是基于一个简单的事实,即标量向量乘法(点积)的符号取决于点的顺序(有关详细信息,请参阅三角形/多边形缠绕规则)求任何 (Pi,Pj) 的最小距离,其中 side(Pi)!=side(pj)
所以首先计算所有点的所有边 O(N) 然后循环遍历所有 Pi 和里面的 for 循环遍历所有 Pj 并搜索最小距离。 如果 Pi 和 Pj 组近似。大小相等,它是 O((N/2)^2)您可以通过与 AB 的“距离”对点 Pi、Pj 进行“排序”来进一步优化搜索
您可以使用另一个点积来执行此操作,这次改为 (B-A) 对它使用垂直向量,比如说 (C-A) 丢弃 Pi2 中的所有点(以及类似的 Pj2) 其中 ((B-A).(P(i1)-A)) 接近于 ((B-A).(P(i2)-A)) 和|((C-A).(P(i1)-A))| 因为这意味着 Pi2 落后于 Pi1(远离 AB) 并且接近 AB 接近 Pi1 的正常值 此优化后的复杂性很大程度上取决于数据集。 应该是 O(N+(Ni*Nj)) 其中 Ni/Nj 是剩余点数 Pi/Pj 你需要2N个点积,Ni*Nj距离比较(不需要sqrt-ed)【讨论】:
第 2 步在 O(mn) 中。有一些更简单的解决方案可以在 O(mn) 中运行。 是的,因此有步骤 3 来代替步骤 2。但是是的,它仍然是 O(N+m*n)。但 N 和 m,n 之间的相关性是未知且非线性的 这里的蛮力方法是我试图避免的。我可以使用迄今为止最好的距离来剔除每个点的搜索窗口,但这并不能提供任何保证。【参考方案4】:解决此问题的典型方法是扫描线算法。假设您有一个坐标系,其中包含所有点和从不同集合中分隔点的线。现在想象一条垂直于分隔线的线以升序从一个点跳到另一个点。为方便起见,您可以旋转和平移点集和分隔线,使分隔线等于 x 轴。扫描线现在与 y 轴平行。
使用扫描线从一个点跳到另一个点,跟踪不同集合中两个点的最短距离。如果前几个点都来自同一组,那么很容易找到一个公式,它会告诉您必须记住哪一个,直到您从另一组中击中第一个点。
假设你总共有 N 个点。您必须对 O(N*log(N)) 中的所有点进行排序。扫描线算法本身将在 O(N) 中运行。
【讨论】:
如果那是最小欧几里得距离,我不支持...欧几里得空间中每边的最近点可能比离分隔线的最近点更远。它有点抽象的图像会更好,可能是我对问题的理解与我应该的不同。 不确定扫描线算法如何在这里工作......当以 y 顺序处理一个新点时,您将如何在恒定时间内确定另一组中最近的点是什么? @Ben:通过跟踪最近的最短距离。如果到另一组最后一个点的新距离更大,那么继续。如果不是,那就是新的最短距离。【参考方案5】:(我不确定这是否与大卫的想法有任何相似之处......我只是在登录后才看到它发表我的想法。)为了争论,假设我们把所有东西都换了,所以划分line 是 x 轴,并按 x 坐标对我们的点进行排序。假设 N 不太大,如果我们沿 x 轴扫描(即遍历我们的 a 和 b 的排序列表),我们可以记录总体最小值和两个通过点列表。扫描中的当前点针对来自另一个列表的每个通过点进行测试,而从列表中的点到(我们扫描的 x 坐标,0)的距离大于或等于整体最小值。在下面的例子中,当到达b2
时,我们可以在a2
停止测试。
scan ->
Y
| a2
|
| a1 a3
X--------------------------
| b1 b3
| b2
【讨论】:
以上是关于直线上最近的一对点的主要内容,如果未能解决你的问题,请参考以下文章
请问一下CAD中空间两条直线的最近距离如何求得,有没有直接的一个命令?谢谢!