• [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是假的吧????

  • 相关阅读:
    MySQL-事务原理
    MySQL-索引原理
    SQL-查询前N条记录
    Shell-配置libpath环境变量
    PG-Vacuum
    python连接mysql数据库
    Spark SQL 基本操作
    spark-shell 交互式编程
    Scala统计学生成绩
    Scala模拟图形绘制
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj1069.html
Copyright © 2020-2023  润新知