平面最近点对

1. 分治法

我们先把所有点按照 \(x\) 坐标为第一关键字,\(y\) 坐标为第二关键字排序。
我们以 \(p_{n/2}\) 为分界点,拆分点集 \(A_1,A_2\),递归下去,直到 \(|A|\le 2\)
设当前 \(A_1,A_2\) 中各自最近距离为 \(d_1,d_2\),令 \(d=\min(d_1,d_2)\)。现在我们合并两个点集的答案。
首先我们将所有 \(x\) 坐标跟 \(x_{n/2}\) 距离不超过 \(d\) 的都放到集合 \(B\) 中。\(B=\{p_i|abs(x_i-x_{n/2})\le d\}\).
我们现在的目的是对于 \(B\) 中的点,找到与其距离不超过 \(d\) 的另一个点。
把考虑到 \(p_i\) 距离不超过 \(d\) 的点,则 \(y\) 轴坐标的差必须 \(\le d\),得到集合 \(C(p_i)=\{p_j|y_j \in [y_i,y_i+d]\}\).
\(C\) 集合可以通过把 \(B\) 里的元素按 \(y\) 坐标排序得到。然后考虑每个 \(C\) 集合中的元素,更新答案。
然而 \(|C|\) 的量级可能是 \(O(n)\) 的,但是可以证明 \(\max|C|\le 7\),所以每个点统计答案都是 \(O(1)\) 的。
因为分治使得两边的最小距离已经被确定,因为两两点距离的限制,所以 \(C\) 中可以放的元素很少。
时间复杂度是 \(O(n\log n)\).

2. 非分治算法

先把所有点按照 \(x\) 坐标为第一关键字,\(y\) 坐标为第二关键字排序。
我们维护一个 multiset,\(y\) 坐标为第一关键字,\(x\) 坐标为第二关键字。
我们顺序加入每个点 \(p_i\),考虑其贡献,首先要把 \(x_i-x_j> d\)\(p_j\) 都删掉,用双指针维护删到哪里。
对于满足 \(|y_i-y_j|\le d\) 的所有点,更新答案。最后把 \(p_i\) 插入到 multiset 中。
关于统计答案这里时间复杂度的证明和分治法大同小异。
由于每个点只会被插入和删除一次,且统计答案部分是 \(O(n)\) 的,复杂度是 \(O(n\log n)\).

3. 随机算法

首先把所有点随机打乱,考虑增量式维护,也就是维护前缀点集的答案。
当我们插入 \(i\) 时,我们将平面以当前的 \(d\) 为边长划分成若干个网格,哈希表存下每个网格中的点。
检查 \(i\) 所在的网格周围九个网格中的所有点,并更新答案。
这里检查次数是 \(O(1)\) 的,因为每个网格最多有 \(4\) 个点。
若答案被更新,那么就重构网格。答案被更新的概率是最近点对中其中一个是 \(i\) 的概率 \(=\) \(\dfrac{1}{i}\).
重构复杂度为 \(O(i)\),所以每次插入期望 \(O(1)\),总的期望复杂度是 \(O(n)\).

posted @ 2024-05-06 10:40  GloriousCc  阅读(4)  评论(0编辑  收藏  举报