代码参考链接: http://t.csdn.cn/flREB
1、一维空间
1.1蛮力法
代码:
import numpy as np
# 求解两个一维点的距离
def Distance(a_point, b_point):
return np.abs(a_point-b_point)
# 蛮力法求解最近两个点的距离
def ClosestPair(points):
mindist = np.inf
close_points = []
for i in range(0, len(points)-1):
distance = Distance(points[i], points[i+1])
if distance < mindist:
# 每次保存最近两个点的信息之前先清空列表
close_points.clear()
mindist = distance
# 保存最近两个点的信息
close_points.append(points[i])
close_points.append(points[i+1])
return mindist, close_points
# 排序
def Sort(points):
print('随机产生的数:', points)
points = sorted(points)
print('排序后:', points)
return ClosestPair(points)
# 随机产生[0,100]中的五个整数
points = np.random.randint(0, 100, 5)
mindist,close_points=Sort(points)
print('最近点对:',close_points)
print('最小距离:',mindist)
结果:
随机产生5个点:
随机产生8个点:
分析:
首先对随机生成的一维点进行排序,时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。然后再遍历排序后的点,计算每一个点和后一个点的距离,于是就找到了距离最近的点对,时间复杂度为
O
(
n
)
O(n)
O(n)。故使用蛮力法解决一维最近点对问题的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
1.2分治法
最近点对问题的分治策略如下:
1、划分:
将集合
S
S
S分成两个子集
S
1
S_{1}
S1和
S
2
S_{2}
S2,根据平衡子问题原则,用
S
S
S中各点坐标的中位数作为分割点,则会得到一个平衡的分割点
m
m
m,使得子集
S
1
S_{1}
S1和
S
2
S_{2}
S2中有个数大致相同的点,会出现以下三种情况:
①最近点对均在集合
S
1
S_{1}
S1中;
②最近点对均在集合
S
2
S_{2}
S2中;
③最近点对分别在集合
S
1
S_{1}
S1和
S
2
S_{2}
S2中。
2、求解子问题:
对于划分阶段的情况①和②可递归求解,如果出现情况③,问题就比较复杂了。
下面讨论情况③:设最近点对是
p
p
p和
q
q
q,那么有
p
∈
S
1
,
q
∈
S
2
p\in S_{1},q\in S_{2}
p∈S1,q∈S2。递归地在
S
1
S_{1}
S1和
S
2
S_{2}
S2上求解最近点对问题,分别得到
S
1
S_{1}
S1和
S
2
S_{2}
S2中的最近距离
d
1
,
d
2
d_{1},d_{2}
d1,d2,令
d
=
m
i
n
(
d
1
,
d
2
)
d=min(d_{1},d_{2})
d=min(d1,d2)。情况③则说明最近点对
(
p
,
q
)
(p,q)
(p,q)在
(
m
−
d
,
m
+
d
)
(m-d,m+d)
(m−d,m+d)的范围内,计算它们的距离。
3、合并:
比较三种情况下的最近点对,取三者之中的距离最小者为问题的解。
代码:
import numpy as np
# 求解两个一维点的距离
def Distance(a_point, b_point):
return np.abs(a_point-b_point)
# 蛮力法求解最近两个点的距离
def ClosestPair(points):
mindist = np.inf
close_points = []
for i in range(0, len(points)-1):
distance = Distance(points[i], points[i+1])
if distance < mindist:
# 每次保存最近两个点的信息之前先清空列表
close_points.clear()
mindist = distance
# 保存最近两个点的信息
close_points.append(points[i])
close_points.append(points[i+1])
return mindist, close_points
# 分治法求解最近两个点的距离
def ClosePoints1(points):
left_points = []
right_points = []
temp_points = []
if len(points) <= 3: # 如果少于3个点,直接用蛮力法求解
distance, close_points = ClosestPair(points)
return distance, close_points
# 求中间位置
midindex = int(len(points)/2)
# 将points分为左右部分
for i in range(len(points)):
if points[i] < points[midindex]:
left_points.append(points[i])
else:
right_points.append(points[i])
distance1, close_points1 = ClosePoints1(left_points)
distance2, close_points2 = ClosePoints1(right_points)
if distance1 < distance2:
min_distance = distance1
close_points = close_points1
else:
min_distance = distance2
close_points = close_points2
# 求中间部分最小距离
for i in range(len(points)): # 把中间宽度为2*min_distance的带状区域内的子集复制到temp_points中
if np.abs(points[i]-points[midindex]) <= min_distance:
temp_points.append(points[i])
distance3 = np.inf
close_points3 = []
for i in range(len(temp_points)-1):
if (temp_points[i+1]-temp_points[i]) >= min_distance:
break
temp_dis = Distance(temp_points[i], temp_points[i+1])
if temp_dis < distance3:
distance3 = temp_dis
close_points3.append(points[i])
close_points3.append(points[i+1])
# 求最近点
if min_distance > distance3:
d = distance3
close_points = close_points3
else:
d = min_distance
close_points=close_points
return d, close_points
# 排序
def Sort(points):
print('随机产生的数:', points)
points = sorted(points)
print('排序后:', points)
return ClosePoints1(points)
# 随机产生[0,100]中整数
points = np.random.randint(0, 100, 8)
mindist,close_points=Sort(points)
print('最近点对:',close_points)
print('最小距离:',mindist)
结果:
分析:
首先对随机生成的一维点进行排序,时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。由于情况①和情况②可递归求解,情况③的时间复杂度是
O
(
n
)
O(n)
O(n),合并子问题解的时间复杂度为
O
(
1
)
O(1)
O(1),则算法的时间复杂性可由递推式表示:
T
(
n
)
=
2
T
(
n
/
2
)
+
O
(
n
)
T(n)=2T(n/2)+O(n)
T(n)=2T(n/2)+O(n),即
T
(
n
)
=
O
(
n
l
o
g
n
)
T(n)=O(nlogn)
T(n)=O(nlogn)。故使用分治法解决一维最近点对问题的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
一维空间的最近点对问题,分治法对于蛮力法而言看起来并没有优势,下面看看二维空间。
2、二维空间
待更新……