最近点对

问题描述

给定平面上 mm 个点的集合 SS,找其中的一对点使得在 nn 个点组成的所有点对中,该点对间的距离最小。

问题分析

简单情形:一维数轴

为了使问题易于理解和分析,先来考虑一维的情形。此时 SS 中的 nn 个点退化为 xx 轴上的 nn 个实数 x1,x2,,xnx_1, x_2, \cdots, x_n。最接近点对即为这 nn 个实数中相差最小的 22 个实数。

假设用 xx 轴上某个点 mmSS 划分为小于 mm 的子集 S1S_1 和大于 mm 的子集 S2S_2。基于平衡子问题的思想,用 SS 中各点坐标的中位数来作分割点。在 S1S_1 中找出其最近点对 {p1,p2}(p1>p2)\{p_1, p_2\} (p_1 > p_2),在 S2S_2 中找出其最近点对 {q1,q2}(q1<q2)\{q_1, q_2\} (q_1 < q_2)。于是最短距离分别为

dS1=p1p2dS2=q1q2 \begin{aligned} d_{S_1} &= \left | p_1 - p_2 \right | \\ d_{S_2} &= \left | q_1 - q_2 \right | \end{aligned}

递归地,SS 中的最近点对要么是 {p1,p2}\{p_1, p_2\},要么是 {q1,q2}\{q_1, q_2\},要么是某个点对 {p3,q3}\{p_3, q_3\},其中 p3S1p_3 \in S_1q3S2q_3 \in S_2。从而用线性时间就可以将 S1S_1 的解和 S2S_2 的解合并成为 SS 的解。

d=min(dS1,dS2,q3p3) \begin{aligned} d = \min (d_{S_1}, d_{S_2}, q_3 - p_3) \end{aligned}

复杂情形:二维平面

选取一垂直线 l:x=ml:x=m 来作为分割直线。其中 mmSS 中各点 xx 坐标的中位数。由此将 SS 分割为 S1S_1S2S_2 两个半平面。

递归地在 S1S_1S2S_2 上找出其最小距离 d1d_1d2d_2 并设 d=min(d1,d2)d=\min(d_1, d_2)SS 中的最接近点对要么是 dd,要么是某个 {p,q}\{p, q\},其中 pS1p \in S_1qS2q \in S_2。如图所示:

对于点 pP1p \in P_1,需要考察 P2P_2 中的各个点和点 pp 之间的距离是否小于 dd。显然 P2P_2 中这样点的 yy 轴坐标一定位于区间 [yd,y+d][y-d, y+d] 之间,而且,这样的点不会超过 66 个。

快速检查 66 个点的方法

  • P1P_1P2P_2 中所有 SS 中点按其 yy 坐标排好序(预处理)。
  • P1P_1 中所有点,对排好序的点列作一次扫描。
  • P1P_1 中每一点最多只要检查 P2P_2 中排好序的相继 66 个点。

算法分析

一维简单情形和二维情形的时间复杂度均为

T(n)=2T(n2)+O(n)=O(nlogn) \begin{aligned} T(n) &= 2 T\left( \frac{n}{2} \right) + O(n) \\ &= O(n \log {n}) \end{aligned}