bzoj1069 凸包+旋转卡壳

问题:在若干个点中取四个点,求围成的四边形的最大面积。
思路:先求个凸包,n^2 枚举对角线,然后旋转卡壳O(1) 更新左右边界即可。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
typedef long long LL;
const int INF=0x7fffffff;
const int N =2e3+10;
int n,m,k;
const double esp =1e-6;
int sgn(double x){return x<-esp?-1:x>esp;}
struct Point{
    void in(){scanf("%lf%lf",&x,&y);}
    double x,y;
    Point(){}
    Point(double x,double y):x(x),y(y){}
    Point operator + (Point o){return Point(x+o.x,y+o.y);}
    Point operator - (Point o){return Point(x-o.x,y-o.y);}
    Point operator * (double len){return Point(x*len,y*len);}
    double operator * (Point o){return x*o.y-y*o.x;}
    double operator / (Point o){return x*o.x+y*o.y;}
    double dis(){return sqrt(x*x+y*y);}
    bool operator < (Point o){
        if(sgn(y-o.y)==0) return sgn(x-o.x)<0;
        return sgn(y-o.y)<0;
    }
    void out(){
        printf("x=%lf,y=%lf\n",x,y);
    }
}p[N],cv[N];
double det(Point a,Point b,Point c){
    return (b-a)*(c-a);
}
double dot(Point a,Point b,Point c){
    return (b-a)/(c-a);
}
Point rot(Point p,double a){

    return Point(cos(a)*p.x-sin(a)*p.y,sin(a)*p.x+cos(a)*p.y);
}
const double pi = acos(-1.0);
bool cmp(Point a,Point b){
    int dir = sgn(det(p[1],a,b));
    if(dir==0) return sgn((a-p[1]).dis()-(b-p[1]).dis())<0;
    return dir>0;
}
int Graham(){
    for(int i=2;i<=n;i++) if(p[i]<p[1]) swap(p[i],p[1]);
    sort(p+2,p+n+1,cmp);
    int tot = 2;
    cv[1]=p[1],cv[2]=p[2];
    p[n+1]=p[1];
    for(int i=3;i<=n+1;i++){
        while(tot>1 && sgn(det(cv[tot-1],cv[tot],p[i]))<=0) tot--;
        cv[++tot]=p[i];
    }
    return tot-1;
}

int main()
{
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)==1){
        for(int i=1;i<=n;i++) p[i].in();
        n = Graham();
       // for(int i=1;i<=n;i++) cv[i].out();
        double res = 0;
        for(int i=1;i<=n;i++){
            int r = i,l=i;
            for(int j=i+1;j<=n;j++){
                Point cur = cv[j]-cv[i];
                //cur.out();
                Point unit = cv[i]+rot(cur,-pi/2);
               // unit.out();
                while(sgn(dot(cv[i],unit,cv[r])-dot(cv[i],unit,cv[r%n+1]))<=0) r=r%n+1;
                while(sgn(dot(cv[i],unit,cv[l])-dot(cv[i],unit,cv[l%n+1]))>=0) l=l%n+1;
                double area = fabs(det(cv[i],cv[j],cv[r]))+fabs(det(cv[i],cv[j],cv[l]));
               // printf("start=%d,end=%d,l=%d,r=%d,area=%lf\n",i,j,l,r,area);
                res=max(res,area);
            }
        }
        res/=2;
        printf("%.3lf\n",res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值