zoukankan      html  css  js  c++  java
  • [bzoj1069][SCOI2007]最大土地面积

    给定n个点,你要选出4个点使得面积最大。n<=2000

    题解:求凸包,然后旋转卡壳,根据某证明,对踵点不会超过3n/2,所以对于每一对对踵点暴力找最远点就可以了。

    复杂度n^2

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    double ans=0;
    int n,rt=1,q[2005],top=0;
    struct P{double x,y;}s[2005];
    double cross(P x,P y,P z)
    {
        double x0=y.x-x.x,xx=z.x-x.x,y0=y.y-x.y,yy=z.y-x.y;
        return x0*yy-xx*y0;
    }
    double area(P x,P y,P z){return fabs(cross(x,y,z))/2.00000;}
    bool cmp(P x,P y){return cross(s[rt],x,y)>0;}
    
    void calc(int s1,int s2)
    {
        double mx1=0,mx2=0;if(s1>s2)swap(s1,s2);
        for(int i=s1+1;i<s2;i++)mx1=max(mx1,area(s[s1],s[s2],s[i]));
        for(int i=s2+1;i<=n;i++)mx2=max(mx2,area(s[s1],s[s2],s[i]));
        for(int i=1;i<s1;i++)mx2=max(mx2,area(s[s1],s[s2],s[i]));
        ans=max(ans,mx1+mx2);
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {    
            scanf("%lf%lf",&s[i].x,&s[i].y);
            if(s[i].y<s[rt].y||(s[i].y==s[rt].y&&s[i].x<s[rt].x)) rt=i;
        }swap(s[rt],s[1]);rt=1;
        sort(s+2,s+n+1,cmp);
        q[++top]=1;q[++top]=2;
        for(int i=3;i<=n;++i)
        {
            while(top>=2&&cross(s[q[top-1]],s[q[top]],s[i])<=0) --top;
            q[++top]=i;    
        }
        for(int i=1;i<=top;i++)s[i]=s[q[i]];s[(n=top)+1]=s[1];
        for(int i=1,j=2;i<=n;calc(i,j),i++)
            while(area(s[i],s[j],s[i+1])<area(s[i],s[j+1],s[i+1]))
                {++j;if(j>n)j=1;}
        printf("%0.3lf",ans);
        return 0;
    }

     update:卡时间卡空间版,用二分求最远点 复杂度nlogn 卡到排行榜RANK 2啦

    #include<cstdio>
    double ans=0;
    int n,rt=1,top=0;
    short*q;
    struct P{double x,y;}*s;
    double cross(P x,P y,P z)
    {
        double x0=y.x-x.x,xx=z.x-x.x,y0=y.y-x.y,yy=z.y-x.y;
        return x0*yy-xx*y0;
    }
    double fabs(double x){return x<0?-x:x;}
    double area(P x,P y,P z){return fabs(cross(x,y,z))/2.00000;}
    bool cmp(P x,P y){return cross(s[rt],x,y)>0;}
    double max(double x,double y){return x<y?y:x;}
    void swap(int x,int y){int t=x;x=y;y=t;}
    void swap(P x,P y){P t=x;x=y;y=t;}
    
    void quickSort(P*arr, int left, int right){
        int i = left, j = right;
        P mid = arr[(i+j)/2];
        while(i <= j){
            while(cmp(arr[i],mid)) i ++;
            while(cmp(mid,arr[j])) j --;
            if(i <= j){
                P tmp;
                tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
                i ++; j --;
            }
        }
        if(i < right) quickSort(arr,i, right);
        if(left < j) quickSort(arr,left, j);
    }
    
    double solve(int l,int r,int s1,int s2)
    {
        double c,c1,c2,mx=0;int mid,ll=l,rr=r;
        while(l<=r)
        {
            mid=(l+r)>>1;c=area(s[s1],s[s2],s[mid]);mx=max(mx,c);
            if(mid==ll)r=mid-1;
            else if(mid==rr) l=mid+1;
            else 
            {    c1=area(s[s1],s[s2],s[mid-1]);
                c2=area(s[s1],s[s2],s[mid+1]);
                if(c1<c2) l=mid+1;else r=mid-1;
            }
        }
        return mx;
    }
    
    void calc(int s1,int s2)
    {
        
        double mx1=0,mx2=0;if(s1>s2)swap(s1,s2);
        /*
        for(int i=s1+1;i<s2;i++)mx1=max(mx1,area(s[s1],s[s2],s[i]));
        for(int i=s2+1;i<=n;i++)mx2=max(mx2,area(s[s1],s[s2],s[i]));
        for(int i=1;i<s1;i++)mx2=max(mx2,area(s[s1],s[s2],s[i]));
        */
        mx1=max(mx1,solve(s1+1,s2-1,s1,s2));
        mx2=max(mx2,max(solve(1,s1-1,s1,s2),solve(s2+1,n,s1,s2)));
        ans=max(ans,mx1+mx2);
    }
    
    int main()
    {
        scanf("%d",&n);q=new short[n+1];s=new P[n+1];
        for(int i=1;i<=n;i++)
        {    
            scanf("%lf%lf",&s[i].x,&s[i].y);
            if(s[i].y<s[rt].y||(s[i].y==s[rt].y&&s[i].x<s[rt].x)) rt=i;
        }swap(s[rt],s[1]);rt=1;
        quickSort(s,2,n);
        q[++top]=1;q[++top]=2;
        for(int i=3;i<=n;++i)
        {
            while(top>=2&&cross(s[q[top-1]],s[q[top]],s[i])<=0) --top;
            q[++top]=i;    
        }
        for(int i=1;i<=top;i++)s[i]=s[q[i]];s[(n=top)+1]=s[1];
        for(int i=1,j=2;i<=n;calc(i,j),i++)
            while(area(s[i],s[j],s[i+1])<area(s[i],s[j+1],s[i+1]))
                {++j;if(j>n)j=1;}
        printf("%0.3lf",ans);
        return 0;
    }

     RANK1是假的吧????

  • 相关阅读:
    [HNOI2002]营业额统计
    HDU 1374
    HDU 3345
    HDU 2089
    Graham扫描法
    Codeforces 1144D Deduction Queries 并查集
    Codeforces 916E Jamie and Tree 线段树
    Codeforces 1167F Scalar Queries 树状数组
    Codeforces 1167E Range Deleting
    Codeforces 749E Inversions After Shuffle 树状数组 + 数学期望
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1069.html
Copyright © 2011-2022 走看看