计算优势点的分而治之算法?
Posted
技术标签:
【中文标题】计算优势点的分而治之算法?【英文标题】:A divide-and-conquer algorithm for counting dominating points? 【发布时间】:2013-10-30 21:24:44 【问题描述】:假设坐标 (x1,y1) 处的一个点支配 如果 x1 ≤ x2 且 y1 ≤ y2 则另一个点 (x2,y2);
我有一组点 (x1,y1) , ....(xn,yn) 我想找到支配对的总数。我可以通过将所有点相互比较来使用蛮力来做到这一点,但这需要时间 O(n2)。相反,我想使用分而治之的方法在 O(n log n) 时间内解决这个问题。
现在,我有以下算法:
绘制一条垂直线,将点集分成两个相等的 Pleft 和 Pright 子集。作为基本情况,如果只剩下两点,我可以直接比较它们。
递归计算 Pleft 和 Pright
中的支配对数一些征服步骤?
问题是我看不到“征服”步骤应该在这里。我想计算从 Pleft 到 Pright 交叉的主导对有多少,但如果不比较两者中的所有点,我不知道该怎么做部分,这需要时间 O(n2)。
谁能给我一个关于如何完成征服步骤的提示?
所以 y 坐标的两半是:1,3,4,5,5 和 5,8,9,10,12
我画了分割线。
【问题讨论】:
【参考方案1】:假设您按 y 坐标升序对两半中的点分别进行排序。现在,查看两半中 y 值最低的点。如果左侧最低点的 y 值低于右侧最低点,则该点受右侧所有点的支配。否则,右边的底点不会支配左边的任何东西。
在任何一种情况下,您都可以从两半中的一个中删除一个点,然后对剩余的排序列表重复该过程。这对每个点做了 O(1) 的工作,所以如果总共有 n 个点,那么 O(n) 的工作(在排序之后)来计算两半中支配对的数量。如果您以前见过,这类似于计算数组中的倒数的算法。
考虑到排序点所需的时间 (O(n log n)),这个征服步骤需要 O(n log n) 时间,给出递归
T(n) = 2T(n / 2) + O(n log n)
根据Master Theorem,这解决了 O(n log2 n)。
但是,您可以加快速度。假设在你开始分治步骤之前,你通过它们的 y 坐标对点进行预排序,做一次 O(n log n) 的工作。使用类似于最接近点对问题的技巧,您可以在每个大小为 n 的子问题上在 O(n) 时间内对每一半中的点进行排序(有关详细信息,请参阅the discussion at this bottom of this page)。这会将重复更改为
T(n) = 2T(n / 2) + O(n)
根据需要求解到 O(n log n)。
希望这会有所帮助!
【讨论】:
好,但我对此感到困惑:“右边的所有点”。这是否意味着左边的这个最低 y 被右边的所有点控制,包括它自己左边的点?示例:左 y = 1,3,4,5,5 ;右 y = 5,8,9,10,12 所以 1 1 小于右 y 中的所有点?但是左边 y 的剩余点3,4,5,5 怎么样?这有点不清楚你的意思是哪个“正确” 另外,我是否应该进行递归调用,直到我在每个子集中只得到 2 分?或者只是将整个列表分成两半,然后只比较 y coord-s? 查看上面的图 - 我使用这个例子 @ERJAN- 这样想。假设您通过绘制一条将它们分成“左”和“右”两半的垂直线来分割这些点。递归计算两半中的支配点数。现在,唯一要考虑的控制点对是一个点在左半边,一个点在右半边的点。右边的任何点已经比左边的任何点有更大的 x 坐标,所以剩下的唯一考虑是右边的点比左边的点有更高的 y 值。我建议的算法提供了一种有效的计数方法...... @ERJAN- ... 跨越分割的支配点数。这能说明问题吗?【参考方案2】:通过这种方式,您有 O(n^2) 仅用于划分子集... 我的方法会有所不同
-
按 X ... O(n.log(n)) 对点进行排序
现在检查 Y
但只检查 X 较大的点(如果您按升序对它们进行排序,则使用较大的索引)
所以现在你有 O(n.log(n)+(n.n/2))
您还可以通过单独的 X 和 Y 测试进一步加快速度,然后组合结果,这将导致 O(n + 3.n.log(n))
-
为您的点添加索引属性
其中 index = 0xYYYYXXXXh 是无符号整数类型
YYYY 是 Y 排序数组中点的索引
XXXX 是 X 排序数组中点的索引
如果您有超过 2^16 个点,请使用大于 32 位的数据类型。
按 X 升序对点进行排序,并将其索引的 XXXX 部分设置为 O1(n.log(n))
按 Y 升序对点进行排序,并将其索引的 YYYY 部分设置为 O2(n.log(n))
按升序索引 O3(n.log(n)) 对点进行排序
如果 (i
但如果您实际上需要为任何点创建所有对
这需要 O4(n.n/2) 所以这种方法不会节省一点时间
如果任何点只需要一对,那么简单的循环就足够了 O4(n-1)
所以在这种情况下 O(n-1+3.n.log(n)) -> ~O(n+3.n.log(n))
希望它有所帮助,...当然,如果您坚持使用这种细分方法,那么我没有更好的解决方案。
PS。为此,您不需要任何额外的递归,只需 3x 排序,任何点只需一个 uint,因此内存需求不是那么大,甚至应该比递归调用一般的细分递归更快
【讨论】:
【参考方案3】:此算法在 O(N*log(N)) 中运行,其中 N 是点列表的大小,它使用 O(1) 额外空间。
执行以下步骤:
-
按 y 坐标(升序)对点列表进行排序,打破平局
x 坐标(升序)。
以相反的顺序遍历排序列表以计算优势点:
如果当前 x 坐标 >= 迄今为止遇到的最大 x 坐标值
然后增加结果并更新最大值。
这是有效的,因为您确定如果所有具有更大 y 坐标的对的 x 坐标都小于当前点,您就找到了一个支配点。排序步骤使其非常高效。
这是 Python 代码:
def my_cmp(p1, p2):
delta_y = p1[1] - p2[1]
if delta_y != 0:
return delta_y
return p1[0] - p2[0]
def count_dom_points(points):
points.sort(cmp = my_cmp)
maxi = float('-inf')
count = 0
for x, y in reversed(points):
if x >= maxi:
count += 1
maxi = x
return count
【讨论】:
以上是关于计算优势点的分而治之算法?的主要内容,如果未能解决你的问题,请参考以下文章