【问题标题】:Choose the closest k points from given n points从给定的 n 个点中选择最近的 k 个点
【发布时间】:2016-06-26 03:44:04
【问题描述】:

给定平面上的一组 U,由 n 个点组成,您可以在恒定时间内计算任意一对点之间的距离。选择一个称为 C 的 U 子集,使得 C 中恰好有 k 个点,并且对于给定的 k,C 中最远的 2 个点之间的距离尽可能小。 1

除了明显的 n-choose-k 解决方案之外,最快的方法是什么?

【问题讨论】:

  • 我感觉这个问题是 NP 完全问题,一个已知 NP 完全问题的简化草图也足够了 :)
  • 完成 - 接受了一个答案(尽管它只是期刊论文的链接)

标签: algorithm language-agnostic geometry computational-geometry


【解决方案1】:

Finding k points with minimum diameter and related problems - Aggarwal, 1991 中显示了一个解决方案。 其中描述的算法有运行时间:O(k^2.5 n log k + n log n)

对于那些无法阅读论文的人: 这个问题被称为 k-diameter 并定义为

找到一组具有最小直径的 k 个点。集合的直径是集合中任意点之间的最大距离。

我无法对所提出的算法进行真正的概述,但它包括计算点的 (3k - 3) 阶 Voronoi 图,然后求解每个 O(kn) Voronoi 集的问题(通过计算一些二分图中的最大独立集)......我想我想说的是,它非常重要,远远超出了采访和这个网站:-)

【讨论】:

  • 这很好,如果“直径”,Aggarwal 表示 k 点之间的最大距离。如果 Aggarwal 的意思是最小的封闭圆的直径,那么这是一个不同的问题。我不会花 31 美元来找出答案 :) 也许有人可以发布他的解决方案的简化多时间版本?
【解决方案2】:

由于这是一个面试问题,所以这是我的解决方案。 (正如 dcn 在下面指出的那样,这并不能保证返回最佳解决方案,尽管它仍然应该是一个不错的启发式方法。很好,dcn!)

  1. 用一个点 P 创建一个集合 Sp
  2. 计算 Sp 中的每个点与它之外的每个点之间的距离,然后将最大距离最小的点添加到 Sp
  3. 重复 2. 直到 Sp 有 k 个点。
  4. 重复1-3,每个点一次作为初始P。取最大距离最小的Sp

Sp里面有O(k)个点,外面有O(n)个点,所以找到最大距离最小的点是O(nk)。我们重复这 k 次,然后重复 整个 过程 n 次,总复杂度为 O(n2k2)

我们可以通过缓存 Sp 中的 任意 点与 Sp 之外的每个点之间的最大距离来改进这一点。如果maxDistanceFromPointInS[pointOutsideS] 是一个 O(1) 哈希表,其中包含每个点 pointOutsideS 和 Sp 内的某个点之间的当前最大距离,那么每次我们添加一个新点 @ 987654323@,我们为 Sp 之外的所有点 p 设置 maxDistanceFromPointInS[p] = Max(maxDistanceFromPointInS[p], distance(newPoint, p))。然后找到最小的最大距离是O(n),在Sp上加一个点是O(n)。重复这 k 次给我们 O((n+n)k) = O(nk)。最后,我们将整个过程重复n次,整体复杂度为O(n2k)

我们可以改进使用堆查找到 O(1) 的最小最大距离,但这不会改变整体复杂性。


顺便说一句,我花了一个小时才写完这一切——我不可能在采访中做到这一点。

【讨论】:

  • 感谢您的指点 - 这不是我问的面试问题,而是在考虑是否应该问,至少看看他们的想法。
  • @wrick:会如何回答这个问题?我认为问一个你自己无法回答的问题是不公平的……
  • @BlueRaja - 这就是为什么我在这里问它希望可能有一个我没有想到的简单解决方案。现在我改变了主意,决定不问这个:)
  • 为什么最小的k-封闭圆不同:考虑一个边长为a的等边三角形。包含所有 3 个端点的最小圆的半径 r=3a/sqrt(a) > a/2。现在取另外三个点与距离 r-epsilon 共线。它们适合半径为 r-epsilon 的圆(小于三角形的圆),但是两个三点簇中的最大距离为 2*(r-epsilon) vs a(对于三角形情况)
  • 为什么你的解决方案不起作用:取一个边长为 a 的等边三角形。现在在平面上再添加三个点:三角形的每个角一个,背对三角形,到三角形角的距离为 b=a-epsilon(类似于星形)。您的算法将在第 2 步的第一次迭代中对每个初始 P 始终采用长度为 b 的边。但是 k=3 的正确解决方案是中间三角形!
【解决方案3】:

这仍然是一个混乱的想法,我不确定它是否真的有效它不起作用。在这里留下错误的答案以供后代使用。

For each point in U
    make a list of the distance to each point in U
    sort the list
    add largest distance to a max-heap.
while any of the lists have more than k elements
    remove max of heap twice
    remove corresponding elements from the two lists they came from
    add the two newly exposed largest elements from those two lists to the heap
Any of the lists left with k elements will list the elements in C

基本上,找到当前看起来可能都在子集中的两个点,并且具有最大的成对距离,然后排除它们都在子集中。重复直到只剩下一种可能的方式来形成一个 k 大小的子集。

这应该是时间复杂度 O((n^2)log(n)) 和空间复杂度 O(n^2)。

【讨论】:

  • 贪心算法将不起作用,因为您最终可能会选择 C={x,y1,y2} 其中 x-y1 和 x-y2 距离很小但 y1 和 y2 彼此相距很远
【解决方案4】:

显然在deterministic polynomial time 中是可行的。

但我不明白他们的算法。他们选择的圆圈似乎总是输入点之一。有人可以对此有所了解或清楚地解释他们的工作(仅第 2 部分就足够了)?

【讨论】:

  • 查看我的评论以获取@BlueRaja - Danny Pflughoeft 的答案。这篇论文是关于一个不同的问题!
  • 所以问题“从给定的 n 个点中找到包含至少 k 个点的最小圆(半径和中心)”和问题“从给定的 n 个点中找到 k 个点的子集,使得最大距离所选子集中的 2 个点之间最小化”是不同的问题吗?
  • 是的,如我的反例所示。但是,我发现您在上面链接的论文中引用了“您的”问题。看看我的回答。
【解决方案5】:

被问到的实际问题似乎很困难。如果这些点不在平面上并且具有任意距离,则通过从 k-clique 减少将是 NP-hard(取任意未加权图,并为缺失的边添加长度无穷大的边,为现有边添加长度为 1 的边——只要“最近的 k 个点”的最大相互距离为 1 而不是无穷大,就会存在大小为 k 的集团)。但是,由于这些点被限制在平面内,因此禁止使用此类距离标签,因此可能会有解决方案。至少,它似乎可以接近近似值。

如果你的面试意味着“包含 k 个点的最小直径圆”,那么以下可能是你在面试中合理地想出的最快正确算法:

对于每个大小为 3 的集合,计算包含这些点的最小圆,并检查每个点是否包含在该圆中。如果包含的数量至少为 k,则相应地更新最小直径。

本质上,这是一个四重嵌套的for循环,所以运行时间是O(n^4)。

【讨论】:

  • 这将给出一个很好的近似值,但它并不完全正确。对于 k=3,假设您有三个点,每个点彼此相隔 1 个单位(直径 = 1.154 ...)。在其他地方,有 2 个点相距 1.1 个单位,中间有第 3 个点(直径 = 1.1)。您的算法将错误地选择后一组三点。
  • 根据我的理解,1.1是这个问题实例的正确返回值,所以这不是反例。 *编辑:哦,好吧,我明白你的意思了。
【解决方案6】:

如果您没有太多异常值,这应该是一个很好的近似解

p = mean center (average x, y) of U
M = U sorted by distance to p
C = M[0:k]

【讨论】:

  • 近似解决方案永远不够好。这个肯定会失败的。
  • @Snowbear:我不想成为不得不教你 NP 完全问题的人......
  • 近似解决方案是棘手的陷阱,因为您必须证明它们的错误范围和运行时间。您当然可以在现实生活中进行其他优化,例如查找集群等
猜你喜欢
  • 2013-10-07
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多