bzoj1069: [SCOI2007]最大土地面积

凸包,(旋转卡壳)。

首先要求的4个点肯定在凸包上,所以先求一个凸包。

然后枚举第一个点,和它的对角线。然后另外俩个点分别与它们构成一个三角形

根据凸多边形的性质,三角形的移动方向是单调的,所以这样枚举的复杂度为O(n^2)。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define eps 1e-6
using namespace std;
const int maxn = 2000 + 10;

struct Vector {
    double x,y;
    Vector(double _x=0,double _y=0):x(_x),y(_y) {}
};

struct Point {
    double x,y;
    Point(double _x=0,double _y=0):x(_x),y(_y) {}    
}p[maxn],s[maxn*2];
int n,sp,pos;
double res;

inline Vector operator- (Point a,Point b) {
    return Vector(a.x-b.x,a.y-b.y);    
}

inline double operator* (Vector a,Vector b) {
    return a.x*b.y-a.y*b.x;    
}

inline int sgn(double x) {
    if(-eps<x && x < eps) return 0;
    else if(x>0) return 1;
    else return -1;    
}

inline bool cmp(Point a,Point b) {
    return (sgn(a.x-b.x)==0?a.y<b.y:a.x<b.x);
}    

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
    sort(p+1,p+n+1,cmp);
    sp=0;
    for(int i=1;i<=n;i++) {
        while(sp>=2 && sgn((s[sp]-s[sp-1])*(p[i]-s[sp-1]))<=0) sp--;    
        s[++sp]=p[i];
    }
    pos=sp;
    for(int i=n-1;i>=1;i--) {
        while(sp>=pos+1 && sgn((s[sp]-s[sp-1])*(p[i]-s[sp-1]))<=0) sp--;
        s[++sp]=p[i];    
    }
    for(int i=1;i<sp;i++) s[sp+i-1]=s[i];
    for(int i=1,p1,p2,p3;i<sp;i++) {
        for(p1=i+1,p2=i+2,p3=i+3;p2<i+sp-1;p2++) {
            while(sgn((s[p2]-s[i])*(s[p1+1]-s[p1]))<0) ++p1;
            while(sgn((s[i]-s[p2])*(s[p3+1]-s[p3]))<0) if(++p3-i>=sp-1) break;
            if(p3-i>=sp-1) break;
            res=max(res,(fabs((s[p2]-s[i])*(s[p1]-s[i]))+fabs((s[p2]-s[i])*(s[p3]-s[i])))/2);
        }
    }
    printf("%.3lf\n",res);
    return 0;    
}
posted @ 2016-06-15 13:30  invoid  阅读(260)  评论(0编辑  收藏  举报