【分治】最接近点对Python实现

### 文章目录

  • [@[toc]](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [问题描述](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [一维最接近点对算法](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [`Python`实现](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [二维最接近点对算法](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [分治算法](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [时间复杂性](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)
  • [`Python`实现](#文章目录 @[toc] 问题描述 一维最接近点对算法 Python实现 二维最接近点对算法 分治算法 时间复杂性 Python实现)

问题描述

  • 给定平面上 n n n个点,找其中的一对点,使得在 n n n个点组成的所有点对中,该点对的距离最小

一维最接近点对算法

Python实现
python 复制代码
import sys


def closest_pair(points):
    points.sort()  # 按照横坐标排序
    min_dist = sys.maxsize  # 初始化最小距离为一个很大的数
    closest = None  # 初始化最接近点对为 None

    for i in range(len(points) - 1):
        dist = abs(points[i] - points[i + 1])  # 计算相邻点对的距离

        if dist < min_dist:
            min_dist = dist
            closest = (points[i], points[i + 1])

    return closest


points = [2, 4, 1, 5, 8, 9, 3]

res = closest_pair(points)

print(f'最接近的点对: {res}')

二维最接近点对算法

分治算法
  • 选取一垂直线 l : x = m l : x = m l:x=m, m m m为 S S S中各点 x x x坐标的中位数,将 S S S分割为 S 1 = {   p ∈ S ∣ x ( p ) ≤ m   } S_{1} = \set{p \in S \mid x(p) \leq m} S1={p∈S∣x(p)≤m}和 S 2 = {   p ∈ S ∣ x ( p ) > m   } S_{2} = \set{p \in S \mid x(p) > m} S2={p∈S∣x(p)>m}
  • 递归地在 S 1 S_{1} S1和 S 2 S_{2} S2上解最接近点对问题,分别得到 S 1 S_{1} S1和 S 2 S_{2} S2中的最小距离 d 1 d_{1} d1和 d 2 d_{2} d2
  • 设 d = min ⁡ {   d 1 , d 2   } d = \min\set{d_{1} , d_{2}} d=min{d1,d2},若 S S S的最接近点对 ( p , q ) (p , q) (p,q)之间的距离小于 d d d,则 p p p和 q q q必分属于 S 1 S_{1} S1和 S 2 S_{2} S2,设 p ∈ S 1 p \in S_{1} p∈S1, q ∈ S 2 q \in S_{2} q∈S2,则 p p p和 q q q距直线 l l l的距离均小于 d d d
  • P 1 P_{1} P1和 P 2 P_{2} P2分别表示直线 l l l的左侧和右侧宽为 d d d的两个垂直长条区域,则 p ∈ P 1 p \in P_{1} p∈P1且 q ∈ P 2 q \in P_{2} q∈P2,此时 P 1 P_{1} P1中所有点与 P 2 P_{2} P2中所有点构成的点对均为最接近点对的候选者,在最坏情况下有 n 2 / 4 n^{2} / 4 n2/4对这样的候选者,但是对于 P 1 P_{1} P1中任一点 p p p, P 2 P_{2} P2中最多只有 6 6 6个点与它构成最接近点对的候选者
    • 实际上对于 P 1 P_{1} P1中任一点 p p p,若与 P 2 P_{2} P2中的点构成最接近点对的候选者,则必有 d i s t a n c e ( p , q ) < d distance(p , q) < d distance(p,q)<d,满足这个条件的 P 2 P_{2} P2中的点一定落在一个 d × 2 d d \times 2d d×2d的矩形 R R R中
    • 可将矩形 R R R的长为 2 d 2d 2d的边 3 3 3等分,将长为 d d d的边 2 2 2等分,由此导出 6 6 6个 ( d / 2 ) × ( 2 d / 3 ) (d / 2) \times (2d / 3) (d/2)×(2d/3)的矩形,矩形 R R R中最多只有 6 6 6个 S S S中的点
  • 合并步骤中,最多只需检查 6 × n / 2 = 3 n 6 \times n / 2 = 3n 6×n/2=3n个候选者,为了确切地知道要检查哪 6 6 6个点,将 p p p和 P 2 P_{2} P2中的点投影到垂直线 l l l上,能与 p p p点一起构成最接近点对候选者的 q q q与 p p p在 l l l上投影点的距离小于 d d d,且这种投影点最多只有 6 6 6个,若将 P 1 P_{1} P1和 P 2 P_{2} P2中所有 S S S中点按其 y y y坐标排好序,则对 P 1 P_{1} P1中所有点,对排好序的点列做一次扫描,就可以找出所有最接近点对的候选者
时间复杂性

T ( n ) = { O ( 1 ) , n < 4 2 T ( n / 2 ) + O ( n ) , n ≥ 4 T(n) = \begin{cases} O(1) , & n < 4 \\ 2 T(n / 2) + O(n) , & n \geq 4 \end{cases} T(n)={O(1),2T(n/2)+O(n),n<4n≥4

T ( n ) = O ( n log ⁡ n ) T(n) = O(n \log{n}) T(n)=O(nlogn)

Python实现
python 复制代码
import math


# 计算两点之间的欧几里德距离
def dist(p1, p2):
    return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)


# 分治法求解最接近点对问题
def closest_pair(points):
    # 如果点集中的点个数小于等于 3 个, 直接计算并返回最小距离对
    if len(points) <= 3:
        min_dist = float('inf')
        min_pair = None

        for i in range(len(points)):
            for j in range(i + 1, len(points)):
                d = dist(points[i], points[j])

                if d < min_dist:
                    min_dist = d
                    min_pair = (points[i], points[j])

        return min_pair

    # 将点集按照 x 坐标排序
    sorted_points = sorted(points, key=lambda p: p[0])

    # 将点集分成左右两部分
    mid = len(sorted_points) // 2

    left_points = sorted_points[:mid]
    right_points = sorted_points[mid:]

    # 递归求解左右两部分的最接近点对
    left_min_pair = closest_pair(left_points)
    right_min_pair = closest_pair(right_points)

    # 取左右两部分最接近点对的最小距离
    if left_min_pair is None:
        min_dist = dist(right_min_pair[0], right_min_pair[1])
        min_pair = right_min_pair
    elif right_min_pair is None:
        min_dist = dist(left_min_pair[0], left_min_pair[1])
        min_pair = left_min_pair
    else:
        left_dist = dist(left_min_pair[0], left_min_pair[1])
        right_dist = dist(right_min_pair[0], right_min_pair[1])

        if left_dist <= right_dist:
            min_dist = left_dist
            min_pair = left_min_pair
        else:
            min_dist = right_dist
            min_pair = right_min_pair

    # 在横跨左右两部分的点中寻找更近的点对
    mid_x = sorted_points[mid][0]
    strip = []

    # 将点集按照 y 坐标排序
    sorted_points = sorted(points, key=lambda p: p[1])

    for point in sorted_points:
        if abs(point[0] - mid_x) < min_dist:
            strip.append(point)

    for i in range(len(strip)):
        for j in range(i + 1, min(i + 7, len(strip))):
            d = dist(strip[i], strip[j])

            if d < min_dist:
                min_dist = d
                min_pair = (strip[i], strip[j])

    return min_dist, min_pair


points = [(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)]

min_dist, min_pair = closest_pair(points)

print(f'最接近的点对为: {min_pair}, 点对距离为 {min_dist}')

相关推荐
m0_594526301 分钟前
Python批量合并多个PDF
java·python·pdf
工业互联网专业15 分钟前
Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现
vue.js·hadoop·python·flask·毕业设计·源码·课程设计
钱钱钱端22 分钟前
【压力测试】如何确定系统最大并发用户数?
自动化测试·软件测试·python·职场和发展·压力测试·postman
慕卿扬23 分钟前
基于python的机器学习(二)—— 使用Scikit-learn库
笔记·python·学习·机器学习·scikit-learn
Json____29 分钟前
python的安装环境Miniconda(Conda 命令管理依赖配置)
开发语言·python·conda·miniconda
小袁在上班1 小时前
Python 单元测试中的 Mocking 与 Stubbing:提高测试效率的关键技术
python·单元测试·log4j
白狐欧莱雅1 小时前
使用python中的pygame简单实现飞机大战游戏
经验分享·python·游戏·pygame
阿_旭1 小时前
基于YOLO11/v10/v8/v5深度学习的维修工具检测识别系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·qt·ai
阿_旭1 小时前
基于YOLO11/v10/v8/v5深度学习的煤矿传送带异物检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
人工智能·python·深度学习·目标检测·yolo11
测试19981 小时前
外包干了2年,快要废了。。。
自动化测试·软件测试·python·面试·职场和发展·单元测试·压力测试