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; }