[SCOI2007]最大土地面积

1069: [SCOI2007]最大土地面积

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 3998  Solved: 1620
[Submit][Status][Discuss]

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

Source

 
[Submit][Status][Discuss]

首先我们可以考虑到如果我们取到了一个最大的四边形,那么这个四边形的四个顶点一定是这些点凸包上的点。也就是说,我们需要先求出这些点的凸包。

那么求出来了之后呢?我们很明显不能暴力求。。。复杂度明显是N^4级别。那么我们应该怎么求呢?考虑四边形性质,可以沿着对角线分成两个三角形,我们只需枚举对角线即可,然后旋转卡壳,求出两边最大三角形的面积求和即可。三角形的面积可以是这个三角形构成平行四边形的面积/2,所以用叉积就可以方便求出。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
#define inf 50000000
#define re register
#define MAXN 5005
using namespace std;
struct node{
    double x,y;
};
node a[MAXN],stackk[MAXN];
double xx,yy;
int n,top;
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
    while(ch=='-') c*=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
inline bool cmp(node a,node b)
{
    if(a.y==b.y) return a.x<b.x;
    return a.y<b.y;
}
inline double cross(node a,node b,node c)
{
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
inline double js(node a,node b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
inline bool cmp1(node a,node b)
{
    int k=cross(stackk[1],a,b);
    if(k>0) return 1;
    else if(k==0) return js(stackk[1],a)<js(stackk[1],b);
    return 0;
}
int main()
{
    n=read();
    for(re int i=1;i<=n;i++)
    scanf("%lf %lf",&a[i].x,&a[i].y);
    sort(a+1,a+n+1,cmp);
    stackk[++top]=a[1];
    sort(a+2,a+n+1,cmp1);
    stackk[++top]=a[2];stackk[++top]=a[3];
    for(re int i=4;i<=n;i++){
        while(top>0&&cross(stackk[top-1],stackk[top],a[i])<=0)
        top--;
        stackk[++top]=a[i];
    }
    stackk[++top]=a[1];
    double ans=0;
    int a,b;
    for(re int x=1;x<=top;x++){
        a=x%top+1;b=(x+2)%top+1;
        for(re int y=x+2;y<=top;y++){
            while(a%top+1!=y&&cross(stackk[x],stackk[a+1],stackk[y])>cross(stackk[x],stackk[a],stackk[y]))
            a=a%top+1;
            while(b%top+1!=x&&cross(stackk[x],stackk[y],stackk[b+1])>cross(stackk[x],stackk[y],stackk[b]))
            b=b%top+1;
            ans=max(cross(stackk[x],stackk[a],stackk[y])+cross(stackk[x],stackk[y],stackk[b]),ans);
        }
    }
    printf("%.3lf",ans/2);
}
原文地址:https://www.cnblogs.com/victorique/p/8682242.html