用于计算支配点的分而治之算法?

时间:2013-10-22 06:29:27

标签: algorithm 2d big-o time-complexity divide-and-conquer

假设坐标(x1,y1)中的一个点支配另一个点(x2,y2),如果x1≤x2且y1≤y2;

我有一组点(x1,y1),....(xn,yn),我想找到支配对的总数。我可以通过将所有点相互比较来使用强力来做到这一点,但这需要时间O(n 2 )。相反,我想用分而治之的方法在时间O(n log n)中解决这个问题。

现在,我有以下算法:

  • 绘制一条垂直线,将点集点分为两个相等的子集P left 和P right 。作为基本情况,如果只剩下两点,我可以直接比较它们。

  • 递归计算P left 和P right

  • 中支配对的数量
  • 一些征服步骤?

问题在于我无法看到“征服”步骤应该在这里。我想计算有多少支配对从P left 到P right ,但我不知道怎么做而不比较两者中的所有点部分,需要时间O(n 2 )。

任何人都可以给我一个关于如何做征服步骤的提示吗? this is my example

所以y坐标的两半是:{1,3,4,5,5}和{5,8,9,10,12}

我画了分界线。

3 个答案:

答案 0 :(得分:6)

假设您按两个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 log 2 n)。

但是,你可以加快速度。假设在你开始划分amd征服步骤之前,你用y坐标预先分配点,做一次O(n log n)工作。使用与最接近的点对问题类似的技巧,然后可以在每个大小为n的子问题(参见the discussion at this bottom of this page)中以O(n)时间对每一半中的点进行排序以获取详细信息。这会将重复发生变为

  

T(n)= 2T(n / 2)+ O(n)

根据需要解决O(n log n)。

希望这有帮助!

答案 1 :(得分:1)

通过这种方式,你只需要O(n ^ 2)来划分子集...
我的方法会有所不同

  1. 按X ... O(n.log(n))
  2. 排序
  3. 现在检查Y.
    • 但只检查具有较大X的点(如果您按升序排序,则使用较大的索引)
  4. 所以现在你有O(n.log(n)+(n.n / 2))
  5. 您还可以通过单独的X和Y测试进一步加快速度,然后结合结果,这将导致O(n + 3.n.log(n))

    1. 为您的积分添加索引属性
      • 其中index = 0xYYYYXXXXh是无符号整数类型
      • YYYY是Y排序数组中的点索引
      • XXXX是X排序数组中的点索引
      • 如果你有超过2 ^ 16个点使用更大的32位数据类型。
    2. 按升序排序X并设置其索引O1的一部分XXX(n.log(n))
    3. 按升序排序,并设置YYYY部分索引O2(n.log(n))
    4. 按升序索引O3(n.log(n))
    5. 对点进行排序
    6. 现在点i支配任何点j if(i< j)
      • 但是如果您需要为任何点创建实际的所有对
      • 这将采取O4(n.n / 2)所以这种方法将节省不了一点时间
      • 如果您只需要单对任何一点,那么简单的循环就足够了O4(n-1)
      • 所以在这种情况下O(n-1 + 3.n.log(n)) - > 〜O(N + 3.n.log(n))的
    7. 希望它有所帮助,...当然,如果你坚持使用细分方法,那么我没有更好的解决方案。

      PS。对于这个你不需要任何额外的递归只需3x排序和任何点只有一个uint因此内存要求不是那么大,甚至应该比递归调用细分递归更快

答案 2 :(得分:0)

此算法在 O(N * log(N))中运行,其中N是点列表的大小,它使用 O(1)额外空格。

执行以下步骤:

  1. 按y坐标(升序)对点列表进行排序,断开连接 x坐标(升序)。
  2. 按相反的顺序浏览排序列表以计算主导点: 如果到目前为止遇到的当前x坐标> = max x-坐标值 然后递增结果并更新最大值
  3. 这是有效的,因为您确定如果所有具有更大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