BZOJ1069 SCOI2007最大土地面积(凸包+旋转卡壳)
求出凸包,显然四个点在凸包上。考虑枚举某点,再移动另一点作为对角线,容易发现剩下两点的最优位置是单调的。过程类似旋转卡壳。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 2010 #define vector point #define nxt(i) (i%tail+1) char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n; double ans; const double eps=1E-8; struct point { double x,y; vector operator +(const vector&a) const { return (vector){x+a.x,y+a.y}; } vector operator -(const vector&a) const { return (vector){x-a.x,y-a.y}; } double operator *(const vector&a) const { return x*a.y-y*a.x; } bool operator <(const point&a) const { return x<a.x||x==a.x&&y<a.y; } }a[N],b[N]; double area(point x,point z,point y) { return (y-x)*(z-x); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj1069.in","r",stdin); freopen("bzoj1069.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y); sort(a+1,a+n+1); int tail=0; for (int i=1;i<=n;i++) { while (tail>1&&(b[tail]-b[tail-1])*(a[i]-b[tail-1])<eps) tail--; b[++tail]=a[i]; } for (int i=n-1;i>=1;i--) { while (tail>1&&(b[tail]-b[tail-1])*(a[i]-b[tail-1])<eps) tail--; b[++tail]=a[i]; } for (int i=1;i<=tail;i++) { int p=nxt(i),q=nxt(i+2); for (int j=i+2;j<=tail;j++) { while (nxt(p)!=i&&area(b[i],b[j],b[p])<area(b[i],b[j],b[nxt(p)])) p=nxt(p); while (nxt(q)!=j&&area(b[i],b[q],b[j])<area(b[i],b[nxt(q)],b[j])) q=nxt(q); ans=max(ans,area(b[i],b[j],b[p])+area(b[i],b[q],b[j]));//cout<<area(b[i],b[j],b[p])+area(b[i],b[q],b[j])<<endl; } } printf("%.3f",ans/2); return 0; }