• 平面最近点对


    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    #define rint register int
    #define ll long long
    using namespace std;
    template<typename xxx>inline void read(xxx &x)
    {
        x=0;int f=1;char c=getchar();
        for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
        for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
        x*=f;
    }
    template<typename xxx>inline void print(xxx x)
    {
        if(x<0){putchar('-');x=-x;}
        if(x>=10) print(x/10);
        putchar(x%10+48);
    }
    const int maxn=2000010;
    const int inf=2e9;
    int n,ans[maxn];
    struct node{
        double x,y;
    }e[maxn];
    inline bool cmp1(node a,node b)
    {
        if(a.x==b.x) return a.y<b.y;
        else return a.x<b.x;
    }
    inline bool cmp2(int a,int b)
    {
        return e[a].y<e[b].y;
    }
    inline double calc(int a,int b)
    {
        return sqrt((e[a].x-e[b].x)*(e[a].x-e[b].x)+(e[a].y-e[b].y)*(e[a].y-e[b].y));
    }
    inline double merge(int l,int r)
    {
        double d=9999999999.0;int k=0;
        if(l==r) return d;
        if(l+1==r) return calc(l,r);
        int mid=(l+r)>>1;
        double d1=merge(l,mid);
        double d2=merge(mid+1,r);
        d=min(d1,d2);
        for(rint i=l;i<=r;++i) if(fabs(e[mid].x-e[i].x)<=d) ans[++k]=i;
        stable_sort(ans+1,ans+k+1,cmp2);
        for(rint i=1;i<=k;++i)
        {
            for(rint j=i+1;j<=k && e[ans[j]].y-e[ans[i]].y<d;++j)
            {
                double dis=calc(ans[i],ans[j]);
                if(dis<d) d=dis;
            }
        }
        return d;
    }
    int main()
    {
        read(n);
        for(rint i=1;i<=n;++i) scanf("%lf%lf",&e[i].x,&e[i].y);
        stable_sort(e+1,e+n+1,cmp1);
        printf("%.4lf",merge(1,n));
    }
    /*神仙算法
    我们充分发扬人类智慧:
    
    将所有点全部绕原点旋转同一个角度,然后按xx坐标排序
    
    根据数学直觉,在随机旋转后,答案中的两个点在数组中肯定不会离得太远
    
    所以我们只取每个点向后的5个点来计算答案
    
    这样速度快得飞起,在n=1000000n=1000000时都可以在1s内卡过
    
     #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<ctime> 
    #define INF 9999999999.0
    using namespace std;
    
    struct node{
        double x,y;
    }a[2000010];
    int n;
    double ans=INF;             //初始化答案为一个很大的数 
    
    bool cmp(node a,node b){
        return a.x<b.x;         //按照横坐标排序 
    }
    double len(node a,node b){
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));//计算两点之间距离 
    }
    void calc(){
        for (int i=1;i<=n;i++){
            for (int j=i+1;j<=i+5;j++){
                double temp;
                temp=len(a[i],a[j]);
                ans=min(ans,temp);
            }
        }
    }
    void around(int ds){
        for (int i=1;i<=n;i++){
            double x=a[i].x,y=a[i].y;//旋转前的点 
            double xn,yn;            //旋转后的点 
            double xyu=0.0,yyu=0.0;  //原点 
            xn= (x - xyu)*cos(ds) - (y - yyu)*sin(ds) + xyu ;
            yn= (x - xyu)*sin(ds) + (y - yyu)*cos(ds) + yyu ;
            a[i].x=xn;
            a[i].y=yn;
        }
        sort(a+1,a+1+n,cmp);        //顺便排序 
        calc();                     //顺便计算 
    }
    
    int main(){
        srand(time(NULL));          //随机数种子 
        for (int i=1;i<=200009;i++){
            a[i].x=INF;a[i].y=INF;  //初始化 
        }
    
        scanf("%d",&n);
        for (int i=1;i<=n;i++){
            scanf("%lf%lf",&a[i].x,&a[i].y);
        }
        around(0);                  //将原图像进行排序并枚举每个点与其后五个点比较 
        around(rand()%360);         //将图像随机(0°~359°)旋转  并排序 并计算 
        around(rand()%360);         //将图像随机(0°~359°)旋转  并排序 并计算 
        printf("%.4lf",ans);
        return 0;
    }
    */ 
    
  • 相关阅读:
    mustcache 模板语法
    java 打印pdf文件
    java从远程服务器获取PDF文件并后台打印(使用pdfFox)
    如何写md格式的文档
    mysql游标的用法及作用
    Spring
    JQuery.extend扩展实现同步post请求
    tp5框架的获取器
    ThinkPHP开启设置子域名笔记
    每天进步一点点
  • 原文地址:https://www.cnblogs.com/Thomastine/p/11862866.html
Copyright © 2020-2023  润新知