bzoj 1069: [SCOI2007]最大土地面积 凸包+旋转卡壳

题目大意:

二维平面有N个点,选择其中的任意四个点使这四个点围成的多边形面积最大

题解:

很容易发现这四个点一定在凸包上
所以我们枚举一条边再旋转卡壳确定另外的两个点即可
旋(xuan2)转(zhuan4)卡(qia3)壳(ke2)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
    x=0;char ch;bool flag = false;
    while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
    while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
inline int cat_max(const int &a,const int &b){return a>b ? a:b;}
inline int cat_min(const int &a,const int &b){return a<b ? a:b;}
const int maxn = 2048;
const double eps = 1e-9;
inline int dcmp(double x){
    if(x < eps && x > -eps) return 0;
    return x > 0 ? 1 : -1;
}
struct Point{
    double x,y;
    Point(double a = .0,double b = .0){
        x=a;y=b;
    }
};
typedef Point Vector;
Vector operator + (const Vector &a,const Vector &b){
    return Vector(a.x + b.x,a.y + b.y);
}
Vector operator - (const Vector &a,const Vector &b){
    return Vector(a.x - b.x,a.y - b.y);
}
double operator * (const Vector &a,const Vector &b){
    return a.x*b.x + a.y*b.y;
}
double operator ^ (const Vector &a,const Vector &b){
    return a.x*b.y - a.y*b.x;
}
double trigonArea(const Point &a,const Point &b,const Point &c){
    return abs((b - a)^(c - a))/2.0;
}
inline bool cmp(const Point &a,const Point &b){
    return dcmp(a.x - b.x) == 0 ? a.y < b.y : a.x < b.x;
}
Point p[maxn],ch[maxn];
int m = 0,n;
void convex(){
    sort(p+1,p+n+1,cmp);m = 0;
    for(int i=1;i<=n;++i){
        while(m > 1 && dcmp((ch[m] - ch[m-1])^(p[i] - ch[m])) <= 0) -- m;
        ch[++m] = p[i];
    }int k = m;
    //printf("%d\n",k);
    for(int i=n-1;i>=1;--i){
        while(m > k && dcmp((ch[m] - ch[m-1])^(p[i] - ch[m])) <= 0) -- m;
        ch[++m] = p[i];
    }if(n > 1) -- m;
    //printf("%d\n",m);
    swap(n,m);swap(p,ch);
}
#define nx(x) ((x) % n + 1)
double spinClipShell(){
    double ret = .0;p[n+1] = p[1];
    for(int i=1;i<=n;++i){
        int x = nx(i);
        int y = nx(i+2);
        for(int j=i+2;j<=n;++j){
            while((nx(x) != j) && dcmp(trigonArea(p[x],p[i],p[j]) - trigonArea(p[x+1],p[i],p[j])) < 0) x = nx(x);
            while((nx(y) != i) && dcmp(trigonArea(p[y],p[i],p[j]) - trigonArea(p[y+1],p[i],p[j])) < 0) y = nx(y);
            ret = max(ret,trigonArea(p[x],p[i],p[j]) + trigonArea(p[y],p[i],p[j]));
        }
    }return ret;
}
int main(){
    read(n);
    for(int i=1;i<=n;++i) scanf("%lf%lf",&p[i].x,&p[i].y);
    convex();printf("%.3lf\n",spinClipShell());
    getchar();getchar();
    return 0;
}

转载于:https://www.cnblogs.com/Skyminer/p/6431747.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值