zoukankan      html  css  js  c++  java
  • 平面最近点对

    题目描述

    给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的

    输入输出格式

    输入格式:

    第一行:n;2≤n≤200000

    接下来n行:每行两个实数:x y,表示一个点的行坐标和列坐标,中间用一个空格隔开。

    输出格式:

    仅一行,一个实数,表示最短距离,精确到小数点后面4位。

    输入输出样例

    输入样例#1: 
    3
    1 1
    1 2
    2 2
    输出样例#1: 
    1.0000

    说明

    0<=x,y<=10^9


    用分治解决这个问题。

    我们正在计算区间$[L, R]$内的答案,假设我们已经计算出了$[L, mid]$和$[mid+1,R]$的答案,我们要求出$[L,R]$答案。

    我们设$[L, mid]$的答案是$d1$,$[mid+1,R]$的答案是$d2$,那么区间[L,R]的答案$d=min(d1, d2)$。

    这是显然不对的。

    为了方便,一下用$S1$代指$[L, mid]$区间,用$S2$代指$[mid+1,R]$区间。

    因为我们只考虑了两个区间内部点的答案,跨区间的两个点有可能成为答案。

    我们设一个在$S1$中的点为$p1$,在$S2$中的点为$p2$。

    那么如果我们暴力枚举,就又成$O(N^2)$的了。

    但我们发现,我们现在的答案已经是$d$了,所以我们根本没必要枚举不可能成为答案的点。

    假如区间中点是$mid$。

    那有用的点其实都在$[mid-d, mid+d]$之间,但是这样最坏情况下还是$O(N^2)$的。

    我们又发现,对于一个点$p1$,可能成为答案的$p2$的$y$坐标的范围,又在$[y[p1]-d, y[p1]+d]$之间。

    对于每个点$p1$,这样的区间是$d imes 2d$这么大的。

    因为我们求出最小距离是$d$,那么在这个有效的区间内最多只有6个点,这个可以画图感受一下。

    所以统计跨越区间的贡献的复杂度变成了线性。

    因为每次分治还要排序,所以总体复杂度是$O(Nlog_2N)$的。

    好像可以边分治边归并,可以去掉一个log,不太了解。


    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    #define reg register 
    #define gc getchar
    inline int read() {
        int res=0;char ch=gc();bool fu=0;
        while(!isdigit(ch)){if(ch=='-')fu=1;ch=gc();}
        while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48), ch=gc();
        return fu?-res:res;
    }
    
    int n;
    struct date {
        double x, y;
    }da[200005];
    int tmp[200005];
    
    bool cmp1(date a, date b) {
        return a.x < b.x;
    }
    
    bool cmp2(int a, int b) {
        return da[a].y < da[b].y;
    }
    
    inline double dist(int i, int j) {
        return sqrt((da[i].x - da[j].x) * (da[i].x - da[j].x) + (da[i].y - da[j].y) * (da[i].y - da[j].y));
    }
    
    double ans;
    
    double Solve(int L, int R)
    {
        double d = 1e20 * 1.0;
        if (L == R) return d;
        if (L + 1 == R) return dist(L, R);
        int mid = (L + R) >> 1;
        d = min(Solve(L, mid), Solve(mid + 1, R));
        int cnt = 0;
        for (reg int i = L ; i <= R ; i ++) 
            if (fabs(da[i].x - da[mid].x) <= d) tmp[++cnt] = i;
        sort(tmp + 1, tmp + 1 + cnt, cmp2);
        for (reg int i = 1 ; i <= cnt ; i ++)
            for (reg int j = i + 1 ; j <= cnt and da[tmp[j]].y - da[tmp[i]].y <= d ; j ++)
                d = min(d, dist(tmp[i], tmp[j]));
        return d;
    }
    
    int main()
    {
        n = read();
        for (reg int i = 1 ; i <= n ; i ++) scanf("%lf%lf", &da[i].x,&da[i].y);
        sort(da + 1, da + 1 + n, cmp1);
        printf("%.4lf
    ", Solve(1, n));
        return 0;
    }
  • 相关阅读:
    fiddler 增加请求时间显示
    es 多字段分词查询优化
    【二分】【预处理】zoj4029 Now Loading!!!
    【数论】【扩展欧几里得】Codeforces Round #484 (Div. 2) E. Billiard
    【set】【multiset】Codeforces Round #484 (Div. 2) D. Shark
    【推导】Codeforces Round #484 (Div. 2) C. Cut 'em all!
    【递推】Codeforces Round #483 (Div. 2) [Thanks, Botan Investments and Victor Shaburov!] D. XOR-pyramid
    【数论】Codeforces Round #483 (Div. 2) [Thanks, Botan Investments and Victor Shaburov!] C. Finite or not?
    【Trie】【枚举约数】Codeforces Round #482 (Div. 2) D. Kuro and GCD and XOR and SUM
    【枚举】【贪心】Codeforces Round #482 (Div. 2) B. Treasure Hunt
  • 原文地址:https://www.cnblogs.com/BriMon/p/9786507.html
Copyright © 2011-2022 走看看