-
Notifications
You must be signed in to change notification settings - Fork 8
/
Rubidium2018.py
101 lines (82 loc) · 2.77 KB
/
Rubidium2018.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# you can write to stdout for debugging purposes, e.g.
# print("this is a debug message")
def closest_split_pair(p_x, p_y, delta, best_pair):
ln_x = len(p_x) # store length - quicker
mx_x = p_x[ln_x // 2][0] # select midpoint on x-sorted array
# Create a subarray of points not further than delta from
# midpoint on x-sorted array
s_y = [x for x in p_y if mx_x - delta <= x[0] <= mx_x + delta]
best = delta # assign best value to delta
ln_y = len(s_y) # store length of subarray for quickness
for i in range(ln_y - 1):
for j in range(i+1, min(i + 7, ln_y)):
p, q = s_y[i], s_y[j]
dst = dist(p, q)
if dst < best:
best_pair = p, q
best = dst
return best_pair[0], best_pair[1], best
def dist(p1, p2):
return max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1]))
def brute(ax):
mi = dist(ax[0], ax[1])
p1 = ax[0]
p2 = ax[1]
ln_ax = len(ax)
if ln_ax == 2:
return p1, p2, mi
for i in range(ln_ax-1):
for j in range(i + 1, ln_ax):
if i != 0 and j != 1:
d = dist(ax[i], ax[j])
if d < mi: # Update min_dist and points
mi = d
p1, p2 = ax[i], ax[j]
return p1, p2, mi
def closest_pair(ax, ay):
ln_ax = len(ax) # It's quicker to assign variable
if ln_ax <= 3:
return brute(ax) # A call to bruteforce comparison
mid = ln_ax // 2 # Division without remainder, need int
Qx = ax[:mid] # Two-part split
Rx = ax[mid:]
# Determine midpoint on x-axis
midpoint = ax[mid][0]
Qy = list()
Ry = list()
for x in ay: # split ay into 2 arrays using midpoint
if x[0] <= midpoint:
Qy.append(x)
else:
Ry.append(x)
# Call recursively both arrays after split
(p1, q1, mi1) = closest_pair(Qx, Qy)
(p2, q2, mi2) = closest_pair(Rx, Ry)
# Determine smaller distance between points of 2 arrays
if mi1 <= mi2:
d = mi1
mn = (p1, q1)
else:
d = mi2
mn = (p2, q2)
# Call function to account for points on the boundary
(p3, q3, mi3) = closest_split_pair(ax, ay, d, mn)
# Determine smallest distance for the array
if d <= mi3:
return mn[0], mn[1], d
else:
return p3, q3, mi3
def solution(X, Y):
a = list(zip(X, Y))
ax = sorted(a, key=lambda x: x[0]) # Presorting x-wise
ay = sorted(a, key=lambda x: x[1]) # Presorting y-wise
(x1, y1), (x2, y2), mi = closest_pair(ax, ay) # Recursive D&C function
lo = 0
high = 10 ** 5
while lo < high:
mid = (lo + high + 1) // 2
if abs(x1 - x2) < 2 * mid and abs(y1 - y2) < 2 * mid:
high = mid - 1
else:
lo = mid
return lo