这道题目一共两种方法,一个乱搞方法,还有一个正解!
先给一个某神奇做法:
我们充分发扬人类智慧,先将所有点按照 x 升序排序再按照 y 升序排序,接着观察题目数据范围,根据前面的排序与数学直觉只要当前的两个点的距离长度大于当前答案,那么就直接退出循环,否则当前答案变为最优答案。这样速度快得飞起,所有数据点都能在 46\mathrm{ms} 内卡过!
接下来给正解方法!分治!
设平面上的点都在点集 S 中。为了将 S 线性分割为大小大致相等的两个子集 S_1 和 S_2,选取一垂直线 l (方程:x = m )作为分割直线,其中 m 为 S 中各点 x 坐标的中位数。由此将 S 分割为:
- S_1 = \{p \in S | p_x \leq m\}
- S_2 = \{p \in S | p_x > m\}
这样 S_1 和 S_2 分别位于直线 l 的左侧和右侧,且满足 S = S_1 \cup S_2。由于 m 是 S 中各点 x 坐标值的中位数,所以 S_1 和 S_2 中的点数大致相等。
递归地在 S_1 和 S_2 上求解最接近点对问题,分别得到 S_1 和 S_2 中的最小距离 \delta_1 和 \delta_2,并令 \delta = \min(\delta_1, \delta_2)。
若 S 的最接近点对 (p, q) 之间的距离 d(p, q) < \delta,则 p 和 q 必分属于 S_1 和 S_2。不妨设 p \in S_1,q \in S_2,此时 p 和 q 距直线 l 的距离均小于 \delta。
用 P_1 和 P_2 分别表示直线 l 的左边和右边宽为 \delta 的两个垂直长条,则 p \in P_1,q \in P_2。P_1 中所有点与 P_2 中所有点构成的点对均为最接近点对的候选者。
在最坏情况下有 \frac{n^2}{4} 对这样的候选者,但 P_1 和 P_2 中的点具有稀疏性质:对于 P_1 中任意一点 p,若它与 P_2 中的点 q 构成最接近点对的候选者,则必有 d(p, q) < \delta,满足此条件的 P_2 中的点一定落在一个 \delta \times 2\delta 的矩形 R 中。
由于 P_2 中任何两个 S 中的点的距离都不小于 \delta,可以推出矩形 R 中最多只有 6 个 S 中的点。将矩形 R 的长为 2\delta 的边 3 等分,长为 \delta 的边 2 等分,可得到 6 个 (\frac{\delta}{2}) \times (\frac{2\delta}{3}) 的矩形。
若矩形 R 中存在多于 6 个 S 中的点,必然存在两点 u, v 使得 d(u, v) \leq \frac{5\delta}{6} < \delta,这与 \delta 的定义矛盾。
因此,对于 P_1 中任一点 p,P_2 中最多只有 6 个点与它构成最接近点对的候选者。在分治法的合并步骤中,最多只需检查 6\times\frac{n}{2} = 3n 对候选者,而非 \frac{n^2}{4} 对。
虽然知道对于 P_1 中每个点 p 最多只需检查 P_2 中的 6 个点,但不清楚具体是哪 6 个点。可以将 p 和 P_2 中所有 S_2 的点投影到垂直线 l 上。
能与 p 构成最接近点对候选者的 S_2 中点一定在矩形 R 中,它们在直线 l 上的投影点距 p 在 l 上投影点的距离小于 \delta,且这种投影点最多只有 6 个。
若将 P_1 和 P_2 中所有 S 的点按其 y 坐标排好序,对 P_1 中所有点 p,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对 P_1 中每一点最多只要检查 P_2 中排好序的相继 6 个点。这样这道题目就被分治解决了!
代码,作者由于只打了乱搞方法的所以只能给乱搞方法的了 qwq
/*输入*/
sort(&a[1],&a[n+1],cmp);//按照 x 排序
sort(&a[1],&a[n+1],cmp2);//按照 y 排序
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
/*计算距离*/
if(sum>=ans)break;//如果大于等于最优答案结束循环
ans=sum;
}
}
/*输出*/
真的打这篇题解,打了很久 qwq