O(nlogn) 分治算法找到可见线

Posted

技术标签:

【中文标题】O(nlogn) 分治算法找到可见线【英文标题】:O(nlogn) divide and conquer algorithm to find visible lines 【发布时间】:2016-01-05 12:14:54 【问题描述】:

我正在尝试解决附图中显示的问题。我得到了分割部分,您可以在其中递归地将线集分成两半,并且可以看到具有最小和最大斜率的线。

我不知道如何做合并部分,我不明白。

直觉上,起初,我认为如果没有三条线在一点相交,所有线最终都会可见。

同样,征服部分是我会取出看不见的线条......据我了解,在征服阶段之前不应该有任何线条被取出。

如果有人可以为我们这些大脑有点慢的人解释一下,我将非常感激! :)

【问题讨论】:

如果没有说明性图像,我们只能猜测......计算机 gfx 中看不见的线条去除通常是通过计算表面法线(如果网格是凸面的)来完成的。在此之前,凹面网格细分为凸面网格。可能还有其他算法利用已知的情况来使用它,但如果没有更多信息,很难说你的例子指的是什么。如果您的网格是实心的(不仅仅是线框),那么您可以使用 Z 排序或 Z 缓冲,但我想这不是您想听到的 【参考方案1】:

考虑一个 3 行示例。您有 2 个选项。 a) 只有 2 行可见 b) 所有 3 行都可见。

因此您需要确定中间的是否可见。为此,您可以计算外部 2 条线的交点(称为 A)。如果A在中间线上方则中间那条是隐藏的,如果在下方则可见(画两个图就很明显了)。

要确定该点是高于还是低于线方程中的坐标 (y = ax + b)。如果y > ax + b 则该点在线上,如果y < ax + b 该点在下方,如果y = ax + b 该点在线上(根据问题不应该发生)。

为了解决您的问题,我将按照斜率的顺序排列线条并尝试将它们添加到解决方案中。每次添加新行时,请检查前一行是否仍然可见,如果不可见则将其删除(根据需要重复多次,因为新行可能会隐藏不止一个前一行)。

如果您坚持要进行合并,则需要在合并行上应用此逻辑,以确定您从中间删除了多少行。

【讨论】:

如果我没记错的话,这将需要 O(n^2) 运行时间。我们可以在 nlgn 中做吗? 它是 NlogN 因为排序。添加和删​​除是 O(N),因为您只添加了一次,然后可能稍后您将其删除(但只有一次)。 每次添加新行并尝试检查它是否可见时,都会与所有其他行一起检查它,这将花费 O(n) 时间。因此,整个算法将花费 O(n^2),因为您正在为所有 n 行执行此操作。 @MoGanji 你只是部分正确。一行可以检查所有其他行并导致 O(N),但是这不可能发生在每一行。一种思考方式是,每行添加一次 O(1)。对于每一行,您都有一堆检查失败并删除一行(可能是 O(N) )和一个通过并停止迭代 O(1) 的检查。所以现在总结一下,我们添加 O(N) 行,我们有 O(N) 检查通过和停止迭代,我们将有 O(N^2) 行删除。但是最后一个不能发生,因为您只能删除 O(N) 行,因为我们总共只有 N @Sorin 这是一个很好的解释,但是,您如何确定在每次迭代中都删除了一行?如果迭代最终没有删除行怎么办?在这种情况下,可能有 O(n^2),对吧?

以上是关于O(nlogn) 分治算法找到可见线的主要内容,如果未能解决你的问题,请参考以下文章

排序时间复杂度为O(nlogn)的排序算法

设计一个采用 O(n log n) 确定的分治算法

(学习6)特殊的分治策略算法——BFPTR

复杂度为 O(n log n) 的分治算法

分治算法总结(未完结)

ST算法