最近点对问题(蛮力法和分治法)

最近点对问题(蛮力法和分治法)


代码参考链接: 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} pS1,qS2。递归地在 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) (md,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、二维空间

待更新……

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值