【洛谷 P4166】 [SCOI2007]最大土地面积(凸包,旋转卡壳)

题目链接
又调了我两个多小时巨亏
直接\(O(n^4)\)枚举4个点显然不行。
数据范围提示我们需要一个\(O(n^2)\)的算法。
于是\(O(n^2)\)枚举对角线,然后在这两个点两边各找一个点使其和对角线构成的三角形面积最大,也就是叉积的绝对值最大。显然具有单调性,于是旋转卡壳维护。

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 50010;
const double eps = 1e-8;
struct point{
    double x, y;
}p[MAXN];
inline double sig(double x){
    return (x > eps) - (x < -eps);
}
int operator == (point a, point b){
    return a.x == b.x && a.y == b.y;
}
double operator * (point a, point b){    // a x b
    return a.x * b.y - b.x * a.y;
}
point operator - (point a, point b){     // a - b
    return (point){ a.x - b.x, a.y - b.y };
}
point operator + (point a, point b){     // a + b
    return (point){ a.x + b.x, a.y + b.y };
}
int cmp(const point a, const point b){   
    return a.x == b.x ? a.y < b.y : a.x < b.x;
}
inline int judge(point a, point b, point c){    //Kab > Kac
    return (b.y - a.y) * (c.x - a.x) >= (c.y - a.y) * (b.x - a.x); 
}
inline double calc(point a, point b, point c){
    return fabs((b - a) * (c - a));
}
int n, top, tp;
point st[MAXN], ts[MAXN];
double ans = 0;
int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
       scanf("%lf%lf", &p[i].x, &p[i].y);
    sort(p + 1, p + n + 1, cmp);
    st[0] = (point){2434321, 2515215};
    for(int i = 1; i <= n; ++i){
       if(p[i] == st[top]) continue;
       while(top > 1 && judge(st[top - 1], st[top], p[i])) --top;
       st[++top] = p[i];
    }
    for(int i = 1; i <= n; ++i){
       if(p[i] == ts[tp]) continue;
       while(tp > 1 && !judge(ts[tp - 1], ts[tp], p[i])) --tp;
       ts[++tp] = p[i];
    }
    for(int i = tp - 1; i; --i) st[++top] = ts[i];
    st[0] = st[--top];
    for(int i = 1; i < top; ++i){
        int k = i + 1, l = (i + 3) % top;
        for(int j = i + 2; j <= top; ++j){
           while(sig(calc(st[i], st[j], st[k]) - calc(st[i], st[j], st[k + 1])) < 0) if(++k > top) k = 1;
           while(sig(calc(st[i], st[j], st[l]) - calc(st[i], st[j], st[l + 1])) < 0) if(++l > top) l = 1;
           ans = max(ans, (calc(st[i], st[j], st[k]) + calc(st[i], st[j], st[l])));
        }
    }
    printf("%.3lf\n", ans / 2);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Qihoo360/p/10325700.html