Divide and Conquer | Set 2 (Closest Pair of Points) | GeeksforGeeks
We are given an array of n points in the plane, and the problem is to find out the closest pair of points in the array.
More Reference:
http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf
Consider a point p ∈ S1. All points of S2 within distance δ of p must lie in a δ × 2δ rectangle R.
How many points can be inside R if each pair is at least δ apart?
• In 2D, this number is at most 6!
• So, we only need to perform 6 × n/2 distance comparisons!
Pick out points whose projection is within δ of p; at most six.
• We can do this for all p, by walking sorted lists of P1 and P2, in total O(n) time.
• The sorted lists for P1, P2 can be obtained from pre-sorting of S1, S2.
• Final recurrence is T(n) = 2T(n/2) + O(n), which solves to T(n) = O(n log n).
http://massivealgorithms.blogspot.com/2014/07/closest-pair-of-points-onlogn.html
http://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/closepoints.pdf
Read full article from Divide and Conquer | Set 2 (Closest Pair of Points) | GeeksforGeeks
We are given an array of n points in the plane, and the problem is to find out the closest pair of points in the array.
As a pre-processing step, input array is sorted according to x coordinates.
1) Find the middle point in the sorted array, we can take P[n/2] as middle point.
2) Divide the given array in two halves. The first subarray contains points from P[0] to P[n/2]. The second subarray contains points from P[n/2+1] to P[n-1].
3) Recursively find the smallest distances in both subarrays. Let the distances be dl and dr. Find the minimum of dl and dr. Let the minimum be d.
4) From above 3 steps, we have an upper bound d of minimum distance. Now we need to consider the pairs such that one point in pair is from left half and other is from right half. Consider the vertical line passing through passing through P[n/2] and find all points whose x coordinate is closer than d to the middle vertical line. Build an array strip[] of all such points.
5) Sort the array strip[] according to y coordinates. This step is O(nLogn). It can be optimized to O(n) by recursively sorting and merging.
6) Find the smallest distance in strip[]. This is tricky. From first look, it seems to be a O(n^2) step, but it is actually O(n). It can be proved geometrically that for every point in strip, we only need to check at most 7 points after it (note that strip is sorted according to Y coordinate). See this for more analysis.
7) Finally return the minimum of d and distance calculated in above step (step 6)
Time Complexity Let Time complexity of above algorithm be T(n). Let us assume that we use a O(nLogn) sorting algorithm. The above algorithm divides all points in two sets and recursively calls for two sets. After dividing, it finds the strip in O(n) time, sorts the strip in O(nLogn) time and finally finds the closest points in strip in O(n) time. So T(n) can expressed as follows
T(n) = 2T(n/2) + O(n) + O(nLogn) + O(n)
T(n) = 2T(n/2) + O(nLogn)
T(n) = T(n x Logn x Logn)
T(n) = 2T(n/2) + O(n) + O(nLogn) + O(n)
T(n) = 2T(n/2) + O(nLogn)
T(n) = T(n x Logn x Logn)
1) Time complexity can be improved to O(nLogn) by optimizing step 5 of the above algorithm. We will soon be discussing the optimized solution in a separate post.
EPI Java Solution:
Find the two closest points ClosestPairPoints.java
public static Pair<Point, Point> findClosestPairPoints(List<Point> P) {
Collections.sort(P, new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
return Integer.valueOf(o1.x).compareTo(o2.x);
}
});
Tuple<Point, Point, Double> ret = findClosestPairPointsHelper(P, 0,
P.size());
return new Pair<>(ret.a, ret.b);
}
// Returns the closest two points and its distance as a tuple.
private static Tuple<Point, Point, Double> findClosestPairPointsHelper(
List<Point> points, int s, int e) {
if (e - s <= 3) { // Brute-force to find answer if there are <= 3 points.
return bruteForce(points, s, e);
}
int mid = (e + s) / 2;
Tuple<Point, Point, Double> lRet = findClosestPairPointsHelper(points, s,
mid);
Tuple<Point, Point, Double> rRet = findClosestPairPointsHelper(points, mid,
e);
Tuple<Point, Point, Double> minLR = lRet.c < rRet.c ? lRet : rRet;
// Stores the points whose x-dis < min_d.
List<Point> remain = new ArrayList<>();
for (Point p : points) {
if (Math.abs(p.x - points.get(mid).x) < minLR.c) {
remain.add(p);
}
}
Tuple<Point, Point, Double> midRet = findClosestPairInRemain(remain,
minLR.c);
return midRet.c < minLR.c ? midRet : minLR;
}
// Returns the closest two points and the distance between them.
private static Tuple<Point, Point, Double> bruteForce(List<Point> P, int s,
int e) {
Tuple<Point, Point, Double> ret = new Tuple<>();
ret.c = Double.MAX_VALUE;
for (int i = s; i < e; ++i) {
for (int j = i + 1; j < e; ++j) {
double dis = distance(P.get(i), P.get(j));
if (dis < ret.c) {
ret = new Tuple<>(P.get(i), P.get(j), dis);
}
}
}
return ret;
}
// Returns the closest two points and its distance as a tuple.
private static Tuple<Point, Point, Double> findClosestPairInRemain(
List<Point> P, double d) {
Collections.sort(P, new Comparator<Point>() {
public int compare(Point o1, Point o2) {
return Integer.valueOf(o1.y).compareTo(o2.y);
}
});
// At most six points in P.
Tuple<Point, Point, Double> ret = new Tuple<>();
ret.c = Double.MAX_VALUE;
for (int i = 0; i < P.size(); ++i) {
for (int j = i + 1; j < P.size() && P.get(j).y - P.get(i).y < d; ++j) {
double dis = distance(P.get(i), P.get(j));
if (dis < ret.c) {
ret = new Tuple<>(P.get(i), P.get(j), dis);
}
}
}
return ret;
}
private static double distance(Point a, Point b) {
return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
private static class Tuple<A, B, C> {
public A a;
public B b;
public C c;
public Tuple() {
}
public Tuple(A aVal, B bVal, C cVal) {
this.a = aVal;
this.b = bVal;
this.c = cVal;
}
}
public static class Point {
public int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "(" + x + ", " + y + ")";
}
}
// A utility function to find the distance beween the closest points of
// strip of given size. All points in strip[] are sorted accordint to
// y coordinate. They all have an upper bound on minimum distance as d.
// Note that this method seems to be a O(n^2) method, but it's a O(n)
// method as the inner loop runs at most 6 times
float
stripClosest(Point strip[],
int
size,
float
d)
{
float
min = d;
// Initialize the minimum distance as d
qsort
(strip, size,
sizeof
(Point), compareY);
// Pick all points one by one and try the next points till the difference
// between y coordinates is smaller than d.
// This is a proven fact that this loop runs at most 6 times
for
(
int
i = 0; i < size; ++i)
for
(
int
j = i+1; j < size && (strip[j].y - strip[i].y) < min; ++j)
if
(dist(strip[i],strip[j]) < min)
min = dist(strip[i], strip[j]);
return
min;
}
// A recursive function to find the smallest distance. The array P contains
// all points sorted according to x coordinate
float
closestUtil(Point P[],
int
n)
{
// If there are 2 or 3 points, then use brute force
if
(n <= 3)
return
bruteForce(P, n);
// Find the middle point
int
mid = n/2;
Point midPoint = P[mid];
// Consider the vertical line passing through the middle point
// calculate the smallest distance dl on left of middle point and
// dr on right side
float
dl = closestUtil(P, mid);
float
dr = closestUtil(P + mid, n-mid);
// Find the smaller of two distances
float
d = min(dl, dr);
// Build an array strip[] that contains points close (closer than d)
// to the line passing through the middle point
Point strip[n];
int
j = 0;
for
(
int
i = 0; i < n; i++)
if
(
abs
(P[i].x - midPoint.x) < d)
strip[j] = P[i], j++;
// Find the closest points in strip. Return the minimum of d and closest
// distance is strip[]
return
min(d, stripClosest(strip, j, d) );
}
// The main functin that finds the smallest distance
// This method mainly uses closestUtil()
float
closest(Point P[],
int
n)
{
qsort
(P, n,
sizeof
(Point), compareX);
// Use recursive function closestUtil() to find the smallest distance
return
closestUtil(P, n);
}
http://www.cs.ucsb.edu/~suri/cs235/ClosestPair.pdf
Consider a point p ∈ S1. All points of S2 within distance δ of p must lie in a δ × 2δ rectangle R.
How many points can be inside R if each pair is at least δ apart?
• In 2D, this number is at most 6!
• So, we only need to perform 6 × n/2 distance comparisons!
• We can do this for all p, by walking sorted lists of P1 and P2, in total O(n) time.
• The sorted lists for P1, P2 can be obtained from pre-sorting of S1, S2.
• Final recurrence is T(n) = 2T(n/2) + O(n), which solves to T(n) = O(n log n).
http://massivealgorithms.blogspot.com/2014/07/closest-pair-of-points-onlogn.html
http://www.cs.cmu.edu/~ckingsf/bioinfo-lectures/closepoints.pdf
Read full article from Divide and Conquer | Set 2 (Closest Pair of Points) | GeeksforGeeks