[凸包] BZOJ1069: [SCOI2007]最大土地面积

题意

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

题解

容易想到凸包。
最优的四边形的端点是落在凸包上的,然后 n2 枚举对角线。在对角线两侧类似旋转卡壳,利用单调性推得最大三角形。这样就是 O(n2) 的。
凸包是三角形?不知道啊反正没管就过了……之后才在discuss上看到,可能选凸包上3点,枚举第4个点可以..吧….

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=2005;
struct Point{
    double x,y;
    Point(double t1=0,double t2=0){ x=t1; y=t2; }
    bool operator < (const Point &b)const{
        if(x<b.x) return true;
        if(x>b.x) return false;
        return y<b.y;
    }   
} a[maxn],ch[maxn];
typedef Point Vector;
Vector operator + (Vector A,Vector B){ return Vector(A.x+B.x,A.y+B.y); }
Vector operator - (Point A,Point B){ return Vector(A.x-B.x,A.y-B.y); }
double Cross(Vector A,Vector B){ return A.x*B.y-A.y*B.x; }
int n,m;
double ans;
int Andrew(){
    sort(a+1,a+n+1);
    int len=0;
    for(int i=1;i<=n;i++){
        while(len>1&&Cross(ch[len]-ch[len-1],a[i]-ch[len-1])<0) len--;
        ch[++len]=a[i];
    }
    int k=len;
    for(int i=n-1;i>=1;i--){
        while(len>k&&Cross(ch[len]-ch[len-1],a[i]-ch[len-1])<0) len--;
        ch[++len]=a[i];
    }
    return len;
}
int main(){
    freopen("bzoj1069.in","r",stdin);
    freopen("bzoj1069.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&a[i].x,&a[i].y);
    m=Andrew();
    for(int i=0;i<=m-1;i++){
        int k1=(i+1)%m,k2=(i+3)%m;
        for(int j=(i+2)%m;(j+1)%m!=i;j=(j+1)%m){
            while(Cross(ch[k1]-ch[i],ch[j]-ch[i])<Cross(ch[(k1+1)%m]-ch[i],ch[j]-ch[i])) k1=(k1+1)%m;
            while(Cross(ch[k2]-ch[j],ch[i]-ch[j])<Cross(ch[(k2+1)%m]-ch[j],ch[i]-ch[j])) k2=(k2+1)%m;
            ans=max(ans,Cross(ch[k1]-ch[i],ch[j]-ch[i])+Cross(ch[j]-ch[i],ch[k2]-ch[i]));
        }
    }
    printf("%.3lf\n",ans/2);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值