[bzoj1069][SCOI2007]最大土地面积--计算几何,旋转卡壳

题目描述

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

Input

第1行一个正整数N,接下来N行,每行2个数x,y,表示该点的横坐标和纵坐标。

Output

最大的多边形面积,答案精确到小数点后3位。

Sample Input

5

0 0

1 0

1 1

0 1

0.5 0.5

Sample Output

1.000

题解

这道题目就是给你一个点集,问你选4个点能构成的最大四边形面积为多少。

首先这四个点肯定都在凸包上,否则答案肯定不是最优的。

然后我们就可以用旋转卡壳去做了,我们可以枚举一条对角线,然后在左半部分和右半部分分别求出面积最大的三角形即可。

至于怎么求面积最大的三角形,大家可以看我的另一篇博客:戳这里

这道题目就讲完了,如果还没有理解的,大家可以看看我的代码。

下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 2010
using namespace std;
struct P{
    double x,y;
}p[maxn];
P operator - (P a,P b)
{
    P tmp;
    tmp.x=a.x-b.x;
    tmp.y=a.y-b.y;
    return tmp;
}
double operator * (P a,P b)
{
    return a.x*b.y-b.x*a.y;
}
double dist(P a,P b)
{
    P tmp=a-b;
    return sqrt(tmp.x*tmp.x+tmp.y*tmp.y);
}
bool cmp(P p1,P p2)
{
    double s=(p1-p[1])*(p2-p[1]);
    return s>0||(s==0&&dist(p1,p[1])>=dist(p2,p[1]));
}
bool judge(int p0,int p1,int p2)
{
    double s=(p[p1]-p[p0])*(p[p2]-p[p0]);
    return s>0||(s==0&&dist(p[p1],p[p0])>=dist(p[p2],p[p0]));
}
double S(P p1,P p2,P p3)
{
    double l1=dist(p1,p2),l2=dist(p2,p3),l3=dist(p3,p1);
    double ar=(l1+l2+l3)/2;
    return sqrt(ar*(ar-l1)*(ar-l2)*(ar-l3));
}
int n;
int q[maxn],top;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)  scanf("%lf%lf",&p[i].x,&p[i].y);
    int fir=1;
    for(int i=2;i<=n;i++)
    {
        if(p[i].y<p[fir].y||(p[i].y==p[fir].y&&p[i].x<p[fir].x)){
            fir=i;
        }
    }
    swap(p[fir],p[1]);
    sort(p+2,p+n+1,cmp);
    p[n+1]=p[1];
    q[++top]=1;q[++top]=2;
    for(int i=3;i<=n+1;i++)
    {
        while(top>1&&judge(q[top-1],i,q[top])==true)  top--;
        q[++top]=i;
    }
    top--;
    double ans=0;
    for(int i=1;i<=top;i++)
    {
        int a=i%top+1,b=(i+2)%top+1;//a,b为两个指针
        for(int j=i+2;j<=top;j++)
        {
            while(a%top+1!=j&&(p[q[a]]-p[q[i]])*(p[q[j]]-p[q[i]])<(p[q[a+1]]-p[q[i]])*(p[q[j]]-p[q[i]])){
                a=a%top+1;//答案比较
            }
            while(b%top+1!=i&&(p[q[j]]-p[q[i]])*(p[q[b]]-p[q[i]])<(p[q[j]]-p[q[i]])*(p[q[b+1]]-p[q[i]])){
                b=b%top+1;//同上
            }
            ans=max(ans,S(p[q[i]],p[q[j]],p[q[a]])+S(p[q[i]],p[q[j]],p[q[b]]));//计算答案
        }
    }
    printf("%.3lf\n",ans);
    return 0;
}

谢谢大家!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值