# closest pair of points using divide and conquer algorithm | a divide and conquer program in python3 to find the smallest distance from a given set of points . ; a class to represent a point in 2d plane ; a utility function to find the distance between two points ; a brute force method to return the smallest distance between two points in p [ ] of size n ; 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 ; initialize the minimum distance as d ; 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 ; a recursive function to find the smallest distance . the array p contains all points sorted according to x coordinate ; if there are 2 or 3 points , then use brute force ; find the middle point ; keep a copy of left and right branch ; consider the vertical line passing through the middle point calculate the smallest distance dl on left of middle point and dr on right side ; find the smaller of two distances ; build an array strip [ ] that contains points close ( closer than d ) to the line passing through the middle point ; < -- required ; find the self . closest points in strip . return the minimum of d and self . closest distance is strip [ ] ; the main function that finds the smallest distance . this method mainly uses closestutil ( ) ; use recursive function closestutil ( ) to find the smallest distance ; 

import math
import copy


class Point ():
    def __init__(self, x, y):
        self .x = x
        self .y = y


def dist(p1, p2):
    return math .sqrt((p1 .x - p2 .x) * (p1 .x - p2 .x) +
                      (p1 .y - p2 .y) * (p1 .y - p2 .y))


def bruteForce(P, n):
    min_val = float('inf')
    for i in range(n):
        for j in range(i + 1, n):
            if dist(P[i], P[j]) < min_val:
                min_val = dist(P[i], P[j])
    return min_val


def stripClosest(strip, size, d):
    min_val = d
    for i in range(size):
        j = i + 1
        while j < size and (strip[j].y - strip[i].y) < min_val:
            min_val = dist(strip[i], strip[j])
            j += 1
    return min_val


def closestUtil(P, Q, n):
    if n <= 3:
        return bruteForce(P, n)
    mid = n // 2
    midPoint = P[mid]
    Pl = P[:mid]
    Pr = P[mid:]
    dl = closestUtil(Pl, Q, mid)
    dr = closestUtil(Pr, Q, n - mid)
    d = min(dl, dr)
    stripP = []
    stripQ = []
    lr = Pl + Pr
    for i in range(n):
        if abs(lr[i].x - midPoint .x) < d:
            stripP .append(lr[i])
        if abs(Q[i].x - midPoint .x) < d:
            stripQ .append(Q[i])
    stripP .sort(key=lambda point: point .y)
    min_a = min(d, stripClosest(stripP, len(stripP), d))
    min_b = min(d, stripClosest(stripQ, len(stripQ), d))
    return min(min_a, min_b)


def closest(P, n):
    P .sort(key=lambda point: point .x)
    Q = copy .deepcopy(P)
    Q .sort(key=lambda point: point .y)
    return closestUtil(P, Q, n)


P = [
    Point(
        2, 3), Point(
            12, 30), Point(
                40, 50), Point(
                    5, 1), Point(
                        12, 10), Point(
                            3, 4)]
n = len(P)
print("The smallest distance is", closest(P, n))

# Expected output:
The smallest distance is 1.4142135623730951