HDU1007 Quoit Design(最近點對問題 經典題型)
原題地址:http://acm.hdu.edu.cn/showproblem.php?pid=1007
題意
一個二維平面上有n個點,求最近兩點的距離的1/2
思路
先按照x軸對所有點進行排序,然後使用分治的思想,選取排序後中間那個點,以該點爲界限分爲左右兩部分,不斷分割直到只有兩個或三個點時,計算最短距離,然後將這些分割的部分進行合併,然而合併稍微複雜了一點。
假設我們一共有n個點,按照上面講的分治方法選取中間的點mid,然後先求1到mid內點的最短距離爲d1,接着求mid+1到n內點的最短距離爲d2,設d=min(d1,d2),這樣我們就求得了左邊和右邊最近點對的距離,但是這樣並未結束,也許最近點對的一個點在左邊,另一個點在右邊,這樣就會漏掉解,所以我們還要以mid點爲中心選取它左右兩邊一定距離內的點進行重新計算。
然而這個距離是多少呢,我們可以這樣想,現在我們的最近距離是d,因爲我們知道兩點的距離dis^2^ =x^2^ + y^2^ ,所以如果兩點在x或y軸上的距離大於已經求得的最近距離d的話,則不管另一個軸上的距離爲多少都不可能比d短了,所以我們只需要按照x軸將mid點附近最大距離爲d的點篩選出來即可。
雖然點都已經篩選出來了,但我們還是不可以在這些點裏面直接求最近點距離,因爲如果點的數量很多的話,還是會超時,所以還需要進一步優化,我們這次按照y軸進行排序,假設排序後有n個點,則求0與1直到n最近的距離,求1與2直到n最近的距離,如果某兩個點n1和n2之間y軸的距離已經超過了之前求得的最近距離d,則可以跳過n1,去計算下一個點n1+1,因爲我們已經按照y軸從小到大進行了排序,如果n1與n2在y軸上的距離超過了d,則n2+1和n1的距離肯定也大於d,因爲n2+1到n1在y軸的距離比n2到n1的距離還大。
AC代碼
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int n;
struct point {
double x;
double y;
} points[101000];
bool cmpx(point p1, point p2) {
return p1.x < p2.x;
}
bool cmpy(int index1, int index2) {
return points[index1].y < points[index2].y;
}
double dis(point p1, point p2) {
double x = p1.x - p2.x;
double y = p1.y - p2.y;
return sqrt(x * x + y * y);
}
double find(int left, int right) {
if (left + 1 == right) {//兩個點
return dis(points[left], points[right]);
}
if (left + 2 == right) {//三個點
return min(dis(points[left], points[left + 1]),
min(dis(points[left], points[right]), dis(points[left + 1], points[right])));
}
int mid = (left + right) >> 1;
double t1 = find(left, mid);
double t2 = find(mid + 1, right);
double t = min(t1, t2);//找到每一個子集中兩點的最短距離
int dp[n];
int len = 0;
for (int i = left; i <= right; i++) {
if (abs(points[i].x - points[mid].x) < t) {
dp[len++] = i;//如果該點到mid的橫座標距離小於t,則其可能是最近點對中的一個
}
}
//按照y軸進行排序
sort(dp, dp + len, cmpy);
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len && points[dp[j]].y - points[dp[i]].y < t; j++) {
t = min(t, dis(points[dp[i]], points[dp[j]]));
}
}
return t;
}
int main() {
while (scanf("%d", &n) != EOF) {
if (!n)break;
for (int i = 0; i < n; i++) {
scanf("%lf %lf", &points[i].x, &points[i].y);
}
sort(points, points + n, cmpx);
printf("%.2f\n", find(0, n - 1) / 2.0);
}
return 0;
}