【题解】平面最近点对(加强版)

洛谷P1429 很久以前就见过并想做的一道题……

但大概是那个时候太蒻竟然一直不敢做呢,想想时间真的过得好快,从写‘Hello World’到如今,其实也不过是短短的一个学期呀。

这道题主要用分治的思想来做,对所有的点排一下序,然后每一次分成两队来处理。若一队的节点数<=3那么就直接暴力求解。可以注意到因为点都是排好序的,所以两边当中的点的距离>= abs(P[i].x - P[mid].x)。那么如果这个距离已经大于我们当前找到的最优答案,显然就不需要再去计算一遍啦。那么我们再把那些还可能含有最优答案的点拿出来暴力处理,因为有前面一个条件的限制,所以实际上这些点的数量是十分有限的。

虽然是道简单的题目,但从不敢做到今天能够自己写出代码来,还是很受鼓励的吧。

#include <bits/stdc++.h>
using namespace std;
#define INF 999999999.00
#define maxn 2005000
int n;
struct node
{
    double x, y;
}P[maxn];
node q1[maxn], q2[maxn];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

double Dis(double x1, double y1, double x2, double y2)
{
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

double Get_ans(int cnt, int cnt2)
{
    double ans = INF;
    for(int i = 1; i <= cnt; i ++)
        for(int j = 1; j <= cnt2; j ++)
            ans = min(ans, Dis(q1[i].x, q1[i].y, q2[j].x, q2[j].y));
    return ans;
}

double Violence(int l, int r)
{
    double ans = INF;
    for(int i = l; i <= r; i ++)
        for(int j = i + 1; j <= r; j ++)
            ans = min(ans, Dis(P[i].x, P[i].y, P[j].x, P[j].y));
    return ans;
}

double Div(int l, int r)
{
    int cnt = 0, cnt2 = 0;
    double ans, ans1, ans2;
    int mid = (l + r) >> 1; 
    if(r - l > 3) ans1 = Div(l, mid), ans2 = Div(mid + 1, r);
    else return Violence(l, r);
    ans = min(ans1, ans2);
    for(int i = mid + 1; i <= r; i ++)
        if(P[i].x - P[mid].x < ans) q1[++ cnt] = P[i];
        else break;
    for(int i = mid; i >= l; i --)
        if(P[mid].x - P[i].x < ans) q2[++ cnt2] = P[i];
        else break;
    return min(ans, Get_ans(cnt, cnt2));
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%lf%lf", &P[i].x, &P[i].y);
    sort(P + 1, P + 1 + n, cmp);
    printf("%.4lf", Div(1, n));
    return 0;
} 

 

posted @ 2018-02-20 19:35  Twilight_Sx  阅读(222)  评论(0编辑  收藏  举报