当前位置: 代码迷 >> 综合 >> bzoj 1069: [SCOI2007]最大土地面积
  详细解决方案

bzoj 1069: [SCOI2007]最大土地面积

热度:45   发布时间:2023-10-29 06:58:50.0

题意

在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大。

题解

其实是一个很简单的几何题啦
显然地,我们要先求一个凸包
然后我们就可以在凸包上暴力枚举两个点
这两个点作为对角线
那么就是吧四边形分成了两个三角形
我们要使得这两个三角形的面积最大
容易发现,第三个点肯定是单调的
于是就维护两个单调的指针扫过去即可
时间复杂度O(n2)O(n2)
一开始T了。。
然后优化了各种常数不如说能一开始我还比较高的大小,后来就直接用叉积比较面积了等等
然后就过了
CODE:

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int N=20005;
const double eps=1e-7;
int n;
struct qq
{double x,y;qq(){}qq (double _x,double _y)    {x=_x;y=_y;}
}s[N];
double mul(qq x,qq y,qq z)
{double x1=x.x-z.x,y1=x.y-z.y;double x2=y.x-z.x,y2=y.y-z.y;return x1*y2-x2*y1;
}
double dis (qq x,qq y)
{return (x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y);
}
bool cmp (qq x,qq y)
{double t=mul(x,y,s[1]);if (abs(t)<eps) return dis(s[1],x)<dis(s[1],y);return t>eps;
}
int sta[N],top;
void get ()
{sort(s+2,s+1+n,cmp);int ToT=n;n=1;for (int u=2;u<=ToT;u++)if (s[u].x!=s[n].x||s[u].y!=s[n].y)s[++n]=s[u];top=2;sta[1]=1;sta[2]=2;for (int u=3;u<=n;u++){while (top>2&&mul(s[u],s[sta[top]],s[sta[top-1]])>-eps) top--;sta[++top]=u;}n=top;for (int u=1;u<=top;u++) s[u-1]=s[sta[u]];
}
int main()
{scanf("%d",&n);for (int u=1;u<=n;u++)  scanf("%lf%lf",&s[u].x,&s[u].y);for (int u=2;u<=n;u++)if (s[u].x<s[1].x||(s[u].x==s[1].x&&s[u].y<s[1].y))swap(s[u],s[1]);get();double ans=0;for (int u=0;u<n;u++){int now=u,now1=(u+2)%n;for (int i=u+2;i<n;i++)//当前这两个点是(u,i) {while (now!=i&&abs(mul(s[now],s[u],s[i]))-abs(mul(s[(now+1)%n],s[u],s[i]))<-eps) now=(now+1)%n;while (now1!=u&&abs(mul(s[u],s[now1],s[i]))-abs(mul(s[u],s[(now1+1)%n],s[i]))<-eps) now1=(now1+1)%n;ans=max(ans,abs(mul(s[now],s[u],s[i])+mul(s[u],s[now1],s[i])));}}printf("%.3lf\n",ans/2);return 0;
}