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

posted @ 2017-03-14 13:35  FallDream  阅读(315)  评论(0编辑  收藏  举报