http://codevs.cn/problem/2319/
题意:给定笛卡尔平面内的若干个点,求最近两点的距离和最远两点的距离,距离是欧氏距离,点数不大于100,000。
对于最近点对考虑分治的做法:用一条直线将所有点分成两部分,对于两部分的点进行分治,然后考虑两部分联合的结果。
可以先把所有点按纵坐标排序,这样就容易用平行于x轴的直线划分。设两边分别求出的结果的较小值是d,我们只需考虑直线两侧离直线距离d以内的所有点即可。
考虑枚举直线某一侧的所有点,对于每个点,在直线另一侧到该点距离小于d的点,是有常数性的限度的。
假设这个点离直线非常非常近,或者就在直线上,以该点为圆心,d为半径所作出的圆在直线另一侧的部分是一个劣弓形,或者半圆。
直线另一侧的一个点若要到该点的距离小于d,则必须落在这个弓形或半圆以内。一个小小的半圆里面能有多少个点呢?注意到在这些点中,所有点对的距离不小于d!
最多只有5个点。事实上,具体算法实现非常简单。对前一半点和后一半点进行分治,然后两重循环枚举前一半点和后一半中的前五个点,计算距离并更新即可。
对于最远点对,显然答案中的两个点一定在整个点集的凸包上,凸包可以用Graham算法来求出。然后旋转卡壳即可。
关于旋转卡壳,我们这里要找的就是在凸包上,与每个点距离最远的另一个点,设凸包上的若干个点依次是p[]号点,离p[i]号点最远的点是f[i]号点。
则对于顺时针依次的p[i]和p[i+1],其答案f[i]和f[i+1]也一定按顺时针排列,这是比较显然的,于是可以用单调队列来求出f[],选出最远的一对即可。