分治法解决最近对问题,按照x坐标分成两堆,mid是最大的x值的下标加上最小的x值的下标除以二,不断递归,直到只有两个或者三个点。两个点或者三个点能够直接处理。然后就是合并,先分别求出左右两堆的最近对,然后让较小的那个距离赋值给d, 以mid为中心,在mid-d和mid+d的范围内找点,因为只有在这个范围内才可能出现比d小的最近距离。找到了就更新d的值。
画图比较简单,画个散点图和一条直线就好了。
import math
import matplotlib.pyplot as plt
import numpy as np
class Point:
def __init__(self):
self.x = 0
self.y = 0
class Apoint:
def __init__(self):
self.index = 0
self.x = 0
self.y = 0
#按照x坐标排序
def cmpx(a):
return a.x
def cmpy(b):
return b.y
#计算两点的距离
def dist(a, b):
return math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y))
def closest(xx, yy, low, high, a, b, d):
if (high - low) == 1:#只有两个点
a = xx[low]
b = xx[high]
d = dist(a, b)
elif (high - low) == 2:#有三个点
dl = dist(xx[low], xx[low+1])
dr = dist(xx[low], xx[high])
d = dist(xx[low+1], xx[high])
if dl < dr and dl < d:
a = xx[low]
b = xx[low+1]
d = dl
elif dr < d:
a = xx[low]
b = xx[high]
d = dr
else:
a = xx[low+1]
b = xx[high]
else:#有多个,分成左右两堆
sl = []
sr = []
temp = Apoint()
mid = (low + high)//2
#以mid为中心
for i in range(high - low + 1):
if yy[i].index <= mid:
sl.append(yy[i])
else:
sr.append(yy[i])
al, bl, dl = closest(xx, sl, low, mid, a, b, d)
ar, br, dr = closest(xx, sr, mid+1, high, a, b, d)
#分别计算左右两堆
if dl < dr:
a, b, d = al, bl, dl
else:
a, b, d = ar, br, dr
z = []
#判断左右两堆点,在mid-d到mid+d的范围内有没有两个以上的点。
for i in range(high - low + 1):
if math.fabs(xx[mid].x - yy[i].x) < d:
temp = Point()
temp.x = yy[i].x
temp.y = yy[i].y
z.append(temp)
for i in range(len(z)):
j = i + 1
while j < len(z) and (z[j].y - z[i].y) < d:
dz = dist(z[j], z[i])
#判断是否比d小
if dz < d:
a = z[i]
b = z[j]
d = dz
j += 1
return a, b, d
#画出图
def closest_pair(xx, n, a, b, d):
if n < 2:
print('n必须大于1')
return -1
else:
xx.sort(key=cmpx)
yy = []
for i in range(n):
temp = Apoint()
temp.index = i
temp.x = xx[i].x
temp.y = xx[i].y
yy.append(temp)
yy.sort(key=cmpy)
a, b, d = closest(xx, yy, 0, n-1, a, b, d)
return a, b, d
n = int(input())
arr = []
a = Point()
b = Point()
d = 0.0
for i in range(n):
t = Point()
t.x = np.random.randint(1, 1000)
t.y = np.random.randint(1, 1000)
arr.append(t)
a, b, d = closest_pair(arr, n, a, b, d)
for p in arr:
plt.scatter(p.x, p.y, marker='o', color='r')
plt.plot([a.x, b.x], [a.y, b.y], c='g')
plt.show()