Skip to content

Commit c866972

Browse files
authored
Merge pull request #566 from AlexAdvent/ClosestPairOfPoints
Create ClosestPairOfPoints
2 parents 0cf7df7 + 0278ca2 commit c866972

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Task. Given 𝑛 points on a plane, find the smallest distance between a pair of two (different) points. Recall
2+
# that the distance between points (𝑥1, 𝑦1) and (𝑥2, 𝑦2) is equal to √︀((𝑥1 − 𝑥2)² + (𝑦1 − 𝑦2)²)
3+
4+
import math
5+
def dist(p1, p2):
6+
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
7+
8+
def closest_split_pair(p_x, p_y, delta, best_pair):
9+
ln_x = len(p_x) # store length - quicker
10+
mx_x = p_x[ln_x // 2][0] # select midpoint on x-sorted array
11+
12+
# Create a subarray of points not further than delta from midpoint on x-sorted array
13+
s_y = [x for x in p_y if mx_x - delta <= x[0] <= mx_x + delta]
14+
15+
best = delta # assign delta value to best
16+
ln_y = len(s_y) # store length of subarray for quickness
17+
for i in range(ln_y - 1):
18+
for j in range(i+1, min(i + 5, ln_y)): # We have to check only next 5 points;
19+
p, q = s_y[i], s_y[j]
20+
dst = dist(p, q)
21+
if dst < best:
22+
best_pair = p, q
23+
best = dst
24+
return best_pair[0], best_pair[1], best
25+
26+
27+
def brute(ax):
28+
mi = dist(ax[0], ax[1])
29+
p1 = ax[0]
30+
p2 = ax[1]
31+
ln_ax = len(ax)
32+
if ln_ax == 2:
33+
return p1, p2, mi
34+
for i in range(ln_ax-1):
35+
for j in range(i + 1, ln_ax):
36+
if i != 0 and j != 1:
37+
d = dist(ax[i], ax[j])
38+
if d < mi: # Update min_dist and points
39+
mi = d
40+
p1, p2 = ax[i], ax[j]
41+
return p1, p2, mi
42+
43+
44+
def closest_pair(ax, ay):
45+
ln_ax = len(ax) # It's quicker to assign variable
46+
if ln_ax <= 3:
47+
return brute(ax) # A call to bruteforce comparison
48+
mid = ln_ax // 2 # Division without remainder, need int
49+
Qx = ax[:mid] # Two-part split
50+
Rx = ax[mid:]
51+
52+
midpoint = ax[mid][0]
53+
Qy = list()
54+
Ry = list()
55+
for x in ay: # split ay into 2 arrays using midpoint
56+
if x[0] < midpoint:
57+
Qy.append(x)
58+
else:
59+
Ry.append(x)
60+
# Call recursively both arrays after split
61+
(p1, q1, mi1) = closest_pair(Qx, Qy)
62+
(p2, q2, mi2) = closest_pair(Rx, Ry)
63+
64+
# Determine smaller distance between points of 2 arrays
65+
if mi1 <= mi2:
66+
d = mi1
67+
mn = (p1, q1)
68+
else:
69+
d = mi2
70+
mn = (p2, q2)
71+
72+
# Call function to account for points on the boundary
73+
(p3, q3, mi3) = closest_split_pair(ax, ay, d, mn)
74+
# Determine smallest distance for the array
75+
if d <= mi3:
76+
return mn[0], mn[1], d
77+
else:
78+
return p3, q3, mi3
79+
80+
81+
def solution(a):
82+
ax = sorted(a, key=lambda x: x[0]) # Presorting x-wise O(nlogn)
83+
ay = sorted(a, key=lambda x: (x[1], x[0])) # Presorting y-wise then x-wise O(nlogn)
84+
p1, p2, mi = closest_pair(ax, ay) # Recursive D&C function
85+
return mi
86+
87+
88+
# Input
89+
points = list()
90+
n = int(input())
91+
for i in range(n):
92+
points.append([int(i) for i in input().split()])
93+
94+
print(solution(points))

0 commit comments

Comments
 (0)