【问题标题】:How to find upper envelopes of intersected lines in O(nlogn)?如何在 O(nlogn) 中找到相交线的上包络线?
【发布时间】:2011-11-17 05:23:12
【问题描述】:

免责声明:是的,这是一个家庭作业,我考虑了几天但找不到方法。

所以有 n 条直线(y= ax + b),我想找到它们的上包络线(图片中的粗体部分)。它必须在 O(nlogn) 中。

我的理解是,我需要找到一种方法来忽略某些行,因为如果我搜索所有行,它就不会是 O(nlogn)。

我正在考虑一种分而治之的方法,以便我可以将列表分成两部分并递归地继续直到解决方案。但后来我不知道如何摆脱一些线条。显然,我不需要考虑图中的一些底线,因为它们不可能为解决方案做出贡献。但我什么也没想到。任何提示表示赞赏。

【问题讨论】:

  • 如果您正在查看最坏情况下的性能,那么丢弃一些行将无助于降低渐近复杂度:很容易构建一个 every 行的情况提供信封的一部分。
  • 正如@NPE 所写,您确实需要考虑每一行。但这没关系 - 只需 O(n) 扫描一次。您需要避免的是考虑每条线 X 线的交点。其中有 n^2 个,所以如果你天真地扫描所有这些,你会得到一个 O(n^2),这比 O(n log(n)) 更糟糕。

标签: algorithm geometry computational-geometry analysis


【解决方案1】:

提示:这个问题基本上是convex hull 问题的对偶。

解决方案:如果您将每条线 y=ax+b 视为一个点 (a,b),并在 (0, -infinity) 添加一个额外的“点”,您应该能够将其输入任何 2D 凸包算法并获得正确的解决方案.

注意:相反,这个问题的任何解决方案也可以用于构建相同 O() 的 2D 凸包算法。


编辑:证明它的请求...

如果点 (x,y) 高于特定线 y=ax+b,则不等式为 ax - y + b > 0

这个不等式也等价于点(-a,b) 位于线(b)=x(-a)+y 上方,其中x 是斜率,y 是截距。

duality 允许我们将点视为线,将线视为点:任何关于点和线的证明或算法都可以映射成一个同样有效的证明或算法,但线和点颠倒了。

在这种情况下:一组 2D 点的凸包确定不是其他点的凸组合的“极值”点,以及连续极值点之间的线。相应地,凸包的对偶版本确定了那些不是其他凸组合的“极端”线,以及连续极端线之间的交点。这是给定行集的包络。

凸包的对偶为您提供输入线集的上包络线和下包络线。由于您只需要线条的上包络线,因此您需要添加一条低于任何可能的常规线的线以消除下包络线。或者,您可以查看解决方案并仅选择坡度增加的交叉点。

相反,这个问题的任何解都可以用来确定一组点的上凸包。运行两次,一次用于行 {(a,b)},一次用于行 {(-a,-b)},将为您提供一个完整的凸包。

【讨论】:

  • 计算凸包不需要一组点。从线上获得一组所有点将是 N^2。这个问题是针对 N Log N 的(这很可能是不可能的)。
  • N Log N 不可能?我的算法实现了这一点
  • 哇,漂亮的观察。如果你能证明它会更好:-)。
  • @LouisRicci stackoverflow.com/users/884862/louis-ricci Duality 允许您使用 y = mx+b 的 m 和 x 将线转换为点。这可以在 O(n) 时间内完成。找到凸包的时间是 O(nlogn)。找到这一点后,我们将凸包转换回来,在 O(n) 时间内反转对偶性。总运行时间为 O(nlogn)。
  • @ErickStone - 将一组线转换为一组线上的点当然是(N),我在谈论将一组线转换为一组线交点 (N^2)。线公式的对偶性和它的点与我的反对无关。我的反对意见仍然有点不稳定,因为您可以使用 Bentley-Ottmann 算法进行交点计算(N Log N)或使用@Simone 建议的方法(尽管我不确定最坏情况下的复杂性是多少)有用的结果)。
【解决方案2】:

首先我们为这些行构造两个不同的二叉搜索树,一个是根据它们的a 排序的行,另一个是根据它们的b 排序的。

现在我们开始考虑行lminlmax,它们是最小和最大a 的行;他们肯定会通过与第二小和第二大线的交点给出的点做出贡献,我们将这两个点添加到上包络线。

现在我们考虑lminlmax 之间的交叉点(xi,yi),理想情况下我们绘制垂直的x = xi 线。我们现在必须确定在坐标y0 s.t. y0 <= yi 中与x = xi 相交的线,并从两棵树中删除所有这些线。

我们如何识别这些线条?我们使用第二棵树找到所有带有b s.t. lmin <= b <= lmax 的行。

最后,我们还将从树中删除 lminlmax

现在我们将对获得的新树进行递归。

【讨论】:

  • 如果函数是二次的,你知道这个算法是否有效吗?因此抛物线而不是线?
  • 它肯定不会像它写的那样工作,因为使用函数是行的假设,但我认为它可能是一个概括
【解决方案3】:

如果我没看错的话,线条总是按照它们的“a”值的顺序对“信封”做出贡献。所以按a对它们进行排序。如果你有两个具有相同的 a,它们是平行的,并且 b 决定哪个在另一个之上(你可以省略较低的)。如果您知道线的顺序,则可以在 O(1) 中计算两条连续线的交点。所以基本上就是排序,也就是O(n log n)。

编辑:好的,其中一个 cmets 是正确的 - 没有不分布到包络的平行线 - 原因是它们会对超出拐点的包络做出贡献。但是,信封段按其“a”的顺序来自行的事实仍然正确(这意味着您始终有开始和结束段)。

问题是如何确定哪条线对信封有贡献,而哪条线对信封没有影响。 您在阵列上扫描一次以找到转折点(必须是“a”切换符号的位置)。你从那里开始一次向下(减少a)和一次向上(增加a)。您计算与下一行的交点 - 如果它在错误的一侧(不减少/增加)x,请跳过它。排序后仍应应用删除平行线(等于 a)的扫描,因为这在计算交点时省略了病理情况。

【讨论】:

  • 您无法计算 O(1) 中两条连续线的交点,因为该点可能不在上包络线上(然后,您必须计算另一个...)。但是,是的,一旦你对行进行了排序,你就可以在 O(N) 中计算包络。
  • 这似乎不是一个完整的解决方案,因为确定一条线是否有助于信封并不像计算出与排序顺序中的下一条线的交点那么简单。跨度>
  • 这显然是不正确的(或至少不完整)。看图片。有些线根本没有贡献(并且不平行)。
  • 如果函数是二次的,你知道这个算法是否有效吗?因此抛物线而不是线?
  • @Bin:不,您没有像简单排序标准这样的“a”。也许它的工作,如果它以某种方式概括(比如从最高功率项中提取因素,考虑更多的拐点 - 找到它们,是否更困难),它是一个强大的 MAYBE。
【解决方案4】:

这是对 Simones 答案的评论,我认为这是不正确的。

现在我们开始考虑线 lmin,lmax,它们是与 最小和最大的a;他们肯定会为 从与第二小的交点和 第二大线,我们将这两个点添加到上部 信封。

不一定是这样。对信封有贡献的部分也可以是从 lmin 到列表中任何其他行的部分。示例:

此外,排除 x=xi 处 y

希望我没有误解您对算法的描述。如果有,请告诉我!

【讨论】:

    【解决方案5】:

    我不知道如何解决这个问题,但请注意,您确实知道最左边和最右边的线(因为 x 趋向于负无穷大和正无穷大),因为它们将具有 a 的最小值和最大值(如x 变大ax 支配b 的任何值。

    鉴于此,您可以找到它们相交的位置并丢弃该点下方的线(我认为)。然后您可能可以以某种方式进行迭代。 (例如,通过在交叉点的 x 坐标处找到最高线,然后重复与原始两条线相交的两个点......)。希望对您有所帮助。

    【讨论】:

      【解决方案6】:

      这是一个输出敏感算法:

      for t = 0, 1, 2 ... do
           k = 2^(2^t)
           arbitrarily partition the segments into ceiling(n/k) subsets each of size at most k
           run any O(nlogn) time algorithm on each group yielding ceiling(n/k) monotone polygonal chains
           find the upper envelope of these monotone polygonal chains, and abort if the output size exceeds k
      end for
      

      运行时间:O(nlogk),其中 k = 答案中的段数。 这本质上是Chan的凸包算法的双重思想

      【讨论】:

        【解决方案7】:

        我知道这个问题已经很老了,但我不同意给出的所有论点,尤其是接受答案中的论点。

        这个问题似乎无法通过一些直截了当的论据来解决。事实上,事实证明,大多数分治算法只能实现 O(n log n a(n)) 的运行时间,其中包含反阿克曼函数 a(n)。

        但是,有一篇论文提供了一个不错但并非微不足道的解决方案: http://www.sciencedirect.com/science/article/pii/0020019089901361

        请注意,该算法是为有限线段设计的。但是,很容易为最小和最大可能的交点提供界限,并将仿射函数“转换”为这些区间上的线段。

        【讨论】:

          【解决方案8】:

          我想象光线从 (0, +INFINITY) 向下发送到我们的一组线。光线的第一个碰撞点是我们包络的一部分。如果任何 3 个连续碰撞不是共线的,则在碰撞点 1 和 2 以及 2 和 3 之间发送更多光线。对于撞击同一条线的连续碰撞,只需在输出集中记录一个。然后,您将使用这组碰撞线来生成每对线之间的实际顶点。

          不幸的是,这可以很好地估计包络,但不是准确的答案(?因为您需要无限多的光线?)。

          Step1) 投射你的第一组光线 {0, -Pi/4, -3Pi/4, -Pi}

          R | L
          1 | Line8
          2 | Line2
          3 | Line2
          4 | Line1
          

          第 2 步)在唯一线(1 和 2,以及 3 和 4)的连续命中之间投射光线。插入结果并剔除内部重复(在两侧具有相同线条的线条命中)。

          R | L
          1 | Line8
          5 |  Line8 * culled out
          6 |  Line8
          7 |  Line5
          8 |  Line2
          2 | Line2 * culled out
          3 | Line2 * culled out
          9 |  Line2 * culled out
          10|  Line2
          11|  Line1
          12|  Line1 * culled out
          4 | Line1
          

          第 3 步)重复第 2 步,直到 (??magic?? 测量精度)。

          第 4 步)通过在结果中的所有连续唯一线之间进行一条线相交来生成包络点列表。

          【讨论】:

          • 哈哈,显然有人不喜欢“抽象”答案
          猜你喜欢
          • 2016-01-05
          • 1970-01-01
          • 1970-01-01
          • 2013-02-03
          • 2013-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-29
          相关资源
          最近更新 更多