bzoj1069 [SCOI2007]最大土地面积

Description
  在某块平面土地上有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

HINT
数据范围 n<=2000, |x|,|y|<=100000

分析:
明确我们要找的点一定在凸包上,
二话不说先来一个凸包

注意:凸包的板子不要打错了

这样我们在凸包上就可以卡壳了

我们枚举四边形的对角线,在四边形的两侧找到距离对角线最远的两个点
计算这样的四边形的面积,取max
因为距离最远的点也是单调的,所以时间O(n^2)

tip

很奇怪我第一次T了

看一下怎么找距离最远的点吧

double k=fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p1+1]]-po[sta[i]]))
        -fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p1]]-po[sta[i]]));
if (dcmp(k)<=0) break;
else p1++;   //p1+1离ip2更远

k是i和p2(对角线)分别和p1+1,p1构成的三角形的面积差
如果k>0说明p1距离对角线更远

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>

using namespace std;

const double INF=1e10;
const double eps=1e-10;
const int N=2010;
struct node{
    double x,y;
    node (double xx=0,double yy=0)
    {
        x=xx;y=yy;
    }
};
node po[N];
int n,sta[N],top;

int dcmp(double x)
{
    if (fabs(x)<eps) return 0;
    else if (x>0) return 1;
    else return -1;
}

int cmp(const node &a,const node &b)
{
    if (dcmp(a.x-b.x)!=0) return a.x<b.x;
    else return a.y<b.y;
}

node operator +(const node &a,const node &b){return node(a.x+b.x,a.y+b.y);}
node operator -(const node &a,const node &b){return node(a.x-b.x,a.y-b.y);}
node operator *(const node &a,const double &b){return node(a.x*b,a.y*b);}
node operator /(const node &a,const double &b){return node(a.x/b,a.y/b);}
bool operator ==(const node &a,const node &b){
    return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}

double mx(double a,double b)
{
    if (dcmp(a-b)>0) return a;
    else return b;
}

double Cross(node x,node y){return x.x*y.y-x.y*y.x;}
double Dot(node x,node y){return x.x*y.x+x.y*y.y;}

void TuB()
{
    int i;
    top=0;
    sort(po+1,po+1+n,cmp);
    for (i=1;i<=n;i++)
    {
        while (top>1&&dcmp(Cross(po[i]-po[sta[top-1]],po[sta[top]]-po[sta[top-1]]))<=0) top--;
        sta[++top]=i;
    }
    int k=top;
    for (i=n-1;i>=1;i--)
    {
        while (top>k&&dcmp(Cross(po[i]-po[sta[top-1]],po[sta[top]]-po[sta[top-1]]))<=0) top--;
        sta[++top]=i;
    }
    if (n>1) top--;
}

double len(node a,node b,node p)
{
    return fabs(Cross(p-a,b-a))/sqrt(Dot(a-b,a-b));
}

double SS(node a,node b,node c,node d)
{
    double f1=Cross(b-a,c-a);
    double f2=Cross(c-a,d-a);
    double r=fabs(Cross(b-a,c-a)+Cross(c-a,d-a))/2;
    return fabs(Cross(b-a,c-a)+Cross(c-a,d-a))/2;
}

void solve()
{
    int i,j;
    double ans=0;
    for (i=1;i<=top;i++) sta[top+i]=sta[i];  //变成环 
    for (i=1;i<top;i++)
    {
        int p1=i+1;
        int p2=p1+1;  //对角线 
        int p3=p2+1;
        for (;p2<top+i-1;p2++)
        {
            while (1)
            {
                double k=fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p1+1]]-po[sta[i]]))
                -fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p1]]-po[sta[i]]));
                if (dcmp(k)<=0) break;
                else p1++;   //p1+1离ip2更远 
            }
            while (1)
            {
                double k=fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p3+1]]-po[sta[i]]))
                -fabs(Cross(po[sta[p2]]-po[sta[i]],po[sta[p3]]-po[sta[i]]));
                if (dcmp(k)<=0) break;
                else p3++;   //p3+1离ip2更远 
            }
            //if (p3>=top+i) break;  //转了超过一圈 
            ans=mx(ans,SS(po[sta[i]],po[sta[p1]],po[sta[p2]],po[sta[p3]]));  //顺时针 
        } 
    }
    printf("%0.3lf",ans);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) 
    scanf("%lf%lf",&po[i].x,&po[i].y);
    TuB();
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值