BZOJ1069 SCOI2007最大土地面积(凸包+旋转卡壳)

时间:2023-12-01 18:09:26

  求出凸包,显然四个点在凸包上。考虑枚举某点,再移动另一点作为对角线,容易发现剩下两点的最优位置是单调的。过程类似旋转卡壳。

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