-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathclosest_pair.py
201 lines (154 loc) · 4.6 KB
/
closest_pair.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import matplotlib.pyplot as plt
import numpy as np
import math
from matplotlib.pyplot import pause
import sys
import random
plt.ion()
colors = []
p = None
pt = 4
def plot_points(points):
global colors
global p
X = []
Y = []
axis = []
# Find X and Y values of points
for (x,y) in points:
X.append(x)
Y.append(y)
# Set up X and Y axises
axis.append(0)
axis.append(max(X)+1)
axis.append(0)
axis.append(max(Y)+1)
# Set up node area
area = [100]*len(points)
# Set up colors
colors = [0.1]*len(points)
p = plt.scatter(X, Y, s=area, c=colors)
plt.axis(axis)
plt.xticks(np.arange(0, max(X)+1, 1.0))
plt.yticks(np.arange(0, max(Y)+1, 1.0))
plt.grid(True)
plt.show()
# Trigger function for closest_pair function
def closest(P, n):
X=list(P)
Y=list(P)
X.sort()
Y = sort_y(Y)
return closest_pair(X, Y, n)
# Recursive Closest Pair function
def closest_pair(X, Y, n):
if n <= 3:
return brute_force(X, n)
mid = n/2
Y_Left = []
Y_Right = []
# Draw vertical line in the middle
draw_line(X[mid][0])
global pt
pause(pt)
print "Middle:", X[mid]
for p in Y:
if p in X[:mid]:
Y_Left.append(p)
else:
Y_Right.append(p)
print "Y_RIGHT: %s" % Y_Right
print "Y_LEFT : %s" % Y_Left
dis_left = closest_pair(X[:mid], Y_Left, mid)
dis_right = closest_pair(X[mid:], Y_Right, n-mid)
min_dis = min(dis_left, dis_right)
print "min_dis: %s" % min_dis
strip = []
for (x,y) in Y:
if abs( x - X[mid][0] ) < min_dis:
strip.append((x,y))
return min(min_dis, strip_closest(strip, min_dis))
# Utility function to calculate min distance between points in strip
def strip_closest(strip, d):
min_d = d
global n
for i,(x,y) in enumerate(strip):
for j in range(i+1, len(strip)):
if (strip[j][1] - strip[i][1]) < min_d and distance(strip[i], strip[j]) < min_d:
min_d = distance(strip[i], strip[j])
return min_d
# Calculates the distance between two points
def distance(a,b):
return math.sqrt( math.pow( (a[0]-b[0]), 2) + math.pow((a[1]-b[1]), 2) )
# Sort points by x value
def sort_y(tuples):
return sorted (tuples,key=lambda last : last[-1])
# Brute force method to calculate distance for n<=3
def brute_force(X, n):
global p
min_d = distance(X[0], X[1])
P1_min = X[0]
P2_min = X[1]
points = p.get_offsets().tolist()
for i,(x,y) in enumerate(X):
for j in range(i+1, n):
if distance(X[i], X[j]) < min_d:
min_d = distance(X[i], X[j])
colors[points.index([X[j][0],X[j][1]])]=0.5
colors[points.index([x,y])]=0.5
P1_min = X[i]
P2_min = X[j]
else:
colors[points.index([X[0][0],X[0][1]])]=0.5
colors[points.index([X[1][0],X[1][1]])]=0.5
draw_line_points(P1_min, P2_min)
plt.text(P1_min[0]+1, P1_min[1]+1, "{0:.2f}".format(min_d), ha='left', rotation=random.randint(-60,60))
global pt
pause(pt)
A=[]
B=[]
area = [100]*len(points)
for x,y in p.get_offsets():
A.append(x)
B.append(y)
plt.scatter(A,B,s=area,c=colors)
return min_d
# Draws vertical line for x value
def draw_line(x):
y_max = int(max(plt.yticks()[0]))
line_y = range(0, y_max+1,1)
line_x = [x]*len(line_y)
line, = plt.plot(line_x,line_y,linewidth=2)
# Draw line between two points
def draw_line_points(a,b):
x=[]
x.append(a[0])
x.append(b[0])
y=[]
y.append(a[1])
y.append(b[1])
line, = plt.plot(x,y,linewidth=1)
def gen_points(r):
a=[]
for i in range(1,r):
a.append( (random.randint(1, r), random.randint(1, r)) )
return a
########## Start Program ########
# 1. Create a list of points
if sys.argv[1] is "1":
points = [(2,3), (10, 1), (3, 25), (23,15),
(18,3), (8,9), (12,30), (25,30),
(9,2), (13,10), (3,4), (5,6),
(22,32), (5,32), (23,9), (19,25),
(14,1), (11,25), (26,26), (12,9),
(18,9), (27,13), (32,13)]
elif sys.argv[1] is "2":
points = [(2,3), (12,30),(25,30), (9,2), (13,10), (3,4), (5,6), (18,9), (27,13), (32,13)]
else:
points = gen_points( int(sys.argv[1]) )
print points
# 2. Draw points on graph
plot_points(points)
# 3. Solve the problem
print "Minimum distance between two points is %s" % closest(points, len(points))
pause(30)