zoukankan      html  css  js  c++  java
  • 【poj3714】 Raid

    http://poj.org/problem?id=3714 (题目链接)

    现在才搞平面最近点对。。感觉有点尴尬

    题意

      给出平面上两组点,每组n个,求两组点之间最短距离

    Solution1

      平面最近点对,分治即可。 

      将点按横坐标排序,然后每次二分成左边和右边分别计算最小距离,再计算中间的最小距离,这里需要把中间符合条件的点按照纵坐标排序,然后当当前枚举的两点的纵坐标之差大于答案时break,否则会TLE。 

    代码1

    // poj3714
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<vector>
    #define inf 2147483640
    #define LL long long
    #define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
    using namespace std;
    inline LL getint() {
        LL x=0,f=1;char ch=getchar();
        while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    const int maxn=1000010;
    struct point {double x,y;int flag;}p[maxn];
    int n,tmp[maxn];
    
    bool cmpx(point a,point b) {
        return a.x==b.x ? a.y<b.y : a.x<b.x;
    }
    bool cmpy(int a,int b) {
        return p[a].y==p[b].y ? p[a].x<p[b].x : p[a].y<p[b].y;
    }
    double dis(point a,point b) {
        return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double solve(int l,int r) {
        double res=1e60;
        if (l==r) return res;
        if (l+1==r) {
            if (p[l].flag==p[r].flag) return res;
            return dis(p[l],p[r]);
        }
        int mid=(l+r)>>1;
        res=solve(l,mid);
        res=min(res,solve(mid+1,r));
        int num=0;
        for (int i=l;i<=r;i++)
            if (fabs(p[i].x-p[mid].x)<=res) tmp[++num]=i;
        sort(tmp+1,tmp+num+1,cmpy);
        for (int i=1;i<=num;i++)
            for (int j=i+1;j<=num;j++) {
                if (fabs(p[tmp[i]].y-p[tmp[j]].y)>=res) break; //剪枝
                if (p[tmp[i]].flag!=p[tmp[j]].flag) res=min(res,dis(p[tmp[i]],p[tmp[j]]));
            }
        return res;
    }
    int main() {
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%d",&n);
            for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y),p[i].flag=0;
            for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i+n].x,&p[i+n].y),p[i+n].flag=1;
            n<<=1;
            sort(p+1,p+1+n,cmpx);
            printf("%.3f
    ",solve(1,n));
        }
        return 0;
    }
    

    Solution2 

      hzwer上惊现平面最近点对的随机化算法(貌似是随机分块),于是我就蒯了过来,虽然并不知道为什么可以这样写,但是好像很厉害的样子。 

      上网搜了下,发现期望复杂度是O(n)的。度娘链接 

      然而= =: 

        

      比分治还跑的慢,坑比东西。

    代码2

    // poj3714
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    inline LL getint() {
        int f,x=0;char ch=getchar();
        while (ch<='0' || ch>'9') {if (ch=='-') f=-1;else f=1;ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    const int maxn=1000010;
    struct point {double x,y;int flag;}p[maxn];
    int n,block,m;
    
    bool cmp(point a,point b) {
        return a.x==b.x ? a.y<b.y : a.x<b.x;
    }
    point rotate(point a,double x) {
        return (point){(double)a.x*cos(x)-(double)a.y*sin(x),(double)a.y*cos(x)+(double)a.x*sin(x),a.flag};
    }
    double dis(point a,point b) {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    int main() {
        int T;scanf("%d",&T);
        while (T--) {
            scanf("%d",&n);
            for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y),p[i].flag=0;
            for (int i=1;i<=n;i++) scanf("%lf%lf",&p[i+n].x,&p[i+n].y),p[i+n].flag=1;
            n<<=1;
            block=(int)sqrt(n);
            m=n/block+(n%block!=0);
            double t=rand()/10000;
            for (int i=1;i<=n;i++) p[i]=rotate(p[i],t);
            sort(p+1,p+1+n,cmp);
            double ans=1e60;
            for (int i=1;i<=m;i++) {
                int t1=block*(i-1),t2=min(block*i,n);
                for (int j=t1;j<=t2;j++)
                    for (int k=t1+1;k<=t2;k++) if (p[j].flag!=p[k].flag) ans=min(ans,dis(p[j],p[k]));
            }
            printf("%.3f
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    LeetCode 252. Meeting Rooms
    LeetCode 161. One Edit Distance
    LeetCode 156. Binary Tree Upside Down
    LeetCode 173. Binary Search Tree Iterator
    LeetCode 285. Inorder Successor in BST
    LeetCode 305. Number of Islands II
    LeetCode 272. Closest Binary Search Tree Value II
    LeetCode 270. Closest Binary Search Tree Value
    LeetCode 329. Longest Increasing Path in a Matrix
    LintCode Subtree
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/5914142.html
Copyright © 2011-2022 走看看