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

题意

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

题解

其实是一个很简单的几何题啦
显然地,我们要先求一个凸包
然后我们就可以在凸包上暴力枚举两个点
这两个点作为对角线
那么就是吧四边形分成了两个三角形
我们要使得这两个三角形的面积最大
容易发现,第三个点肯定是单调的
于是就维护两个单调的指针扫过去即可
时间复杂度 O(n2) O ( n 2 )
一开始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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值