HDU1007 Quoit Design(最近點對問題 經典題型)

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章