Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A divide-and-conquer algorithm for counting dominating points?

Let's say that a point at coordinate (x1,y1) dominates another point (x2,y2) if x1 ≤ x2 and y1 ≤ y2;

I have a set of points (x1,y1) , ....(xn,yn) and I want to find the total number of dominating pairs. I can do this using brute force by comparing all points against one another, but this takes time O(n2). Instead, I'd like to use a divide-and-conquer approach to solve this in time O(n log n).

Right now, I have the following algorithm:

  • Draw a vertical line dividing the set of points points into two equal subsets of Pleft and Pright. As a base case, if there are just two points left, I can compare them directly.

  • Recursively count the number of dominating pairs in Pleft and Pright

  • Some conquer step?

The problem is that I can't see what the "conquer" step should be here. I want to count how many dominating pairs there are that cross from Pleft into Pright, but I don't know how to do that without comparing all the points in both parts, which would take time O(n2).

Can anyone give me a hint about how to do the conquer step? this is my example

so the 2 halves of y coordinates are : {1,3,4,5,5} and {5,8,9,10,12}

i draw the division line.

like image 809
ERJAN Avatar asked Oct 22 '13 06:10

ERJAN


2 Answers

Suppose you sort the points in both halves separately in ascending order by their y coordinates. Now, look at the lowest y-valued point in both halves. If the lowest point on the left has a lower y value than the lowest point on the right, then that point is dominated by all points on the right. Otherwise, the bottom point on the right doesn't dominate anything on the left.

In either case, you can remove one point from one of the two halves and repeat the process with the remaining sorted lists. This does O(1) work per point, so if there are n total points, this does O(n) work (after sorting) to count the number of dominating pairs across the two halves. If you've seen it before, this is similar to the algorithm for counting inversions in an array).

Factoring in the time required to sort the points (O(n log n)), this conquer step takes O(n log n) time, giving the recurrence

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

This solves to O(n log2 n) according to the Master Theorem.

However, you can speed this up. Suppose that before you start the divide amd conquer step that you presort the points by their y coordinates, doing one pass of O(n log n) work. Using tricks similar to the closest pair of points problem, you can then get the points in each half sorted in O(n) time on each subproblem of size n (see the discussion at this bottom of this page) for details). That changes the recurrence to

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

Which solves to O(n log n), as required.

Hope this helps!

like image 118
templatetypedef Avatar answered Oct 14 '22 19:10

templatetypedef


Well in this way you have O(n^2) just for division to subsets...
My approach would be different

  1. sort points by X ... O(n.log(n))
  2. now check for Y
    • but check only points with bigger X (if you sort them ascending then with larger index)
  3. so now you have O(n.log(n)+(n.n/2))

You can also further speed things up by doing separate X and Y test and after that combine the result, that would leads O(n + 3.n.log(n))

  1. add index attribute to your points
    • where index = 0xYYYYXXXXh is unsigned integer type
    • YYYY is index of point in Y-sorted array
    • XXXX is index of point in X-sorted array
    • if you have more than 2^16 points use bigger then 32-bit data-type.
  2. sort points by ascending X and set XXXX part of their index O1(n.log(n))
  3. sort points by ascending Y and set YYYY part of their index O2(n.log(n))
  4. sort points by ascending index O3(n.log(n))
  5. now point i dominates any point j if (i < j)
    • but if you need to create actually all the pairs for any point
    • that would take O4(n.n/2) so this approach will save not a bit of time
    • if you need just single pair for any point then simple loop will suffice O4(n-1)
    • so in this case O(n-1+3.n.log(n)) -> ~O(n+3.n.log(n))

hope it helped,... of course if you are stuck with that subdivision approach than i have no better solution for you.

PS. for this you do not need any additional recursion just 3x sorting and only one uint for any point so the memory requirements are not that big and even should be faster than recursive call to subdivision recursion in general

like image 45
Spektre Avatar answered Oct 14 '22 19:10

Spektre