【计算几何】洛谷 P4166 [SCOI2007] 最大土地面积

注意生成凸包时要把点去重,然后用旋转卡壳解决即可。

#include <bits/stdc++.h>

// from: cpp.json
#define INF 8e18
#define int long long
using namespace std;

// 几何模板
template<class T>
struct Point {
    T x; 
    T y; 

    Point(const T &x_ = 0, const T &y_ = 0) : x(x_), y(y_) {}

    template<class U>
    operator Point<U>() const {
        return Point<U>(U(x), U(y));
    }

    Point &operator+=(const Point &p) & {
        x += p.x;
        y += p.y;
        return *this;
    }
    
    Point &operator-=(const Point &p) & {
        x -= p.x;
        y -= p.y;
        return *this;
    }
    
    Point &operator*=(const T &v) & {
        x *= v;
        y *= v;
        return *this;
    }
    
    Point &operator/=(const T &v) & {
        x /= v;
        y /= v;
        return *this;
    }
    
    Point operator-() const {
        return Point(-x, -y);
    }
    
    friend Point operator+(Point a, const Point &b) {
        return a += b;
    }
    
    friend Point operator-(Point a, const Point &b) {
        return a -= b;
    }
    
    friend Point operator*(Point a, const T &b) {
        return a *= b;
    }
    
    friend Point operator/(Point a, const T &b) {
        return a /= b;
    }
    
    friend Point operator*(const T &a, Point b) {
        return b *= a;
    }
        
    friend bool operator==(const Point &a, const Point &b) {
        return a.x == b.x && a.y == b.y;
    }

    friend bool operator<(Point a, Point b) {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
    
    friend std::istream &operator>>(std::istream &is, Point &p) {
        return is >> p.x >> p.y;
    }
    
    friend std::ostream &operator<<(std::ostream &os, const Point &p) {
        return os << "(" << p.x << ", " << p.y << ")";
    }
};

template<class T>
T cross(const Point<T> &a, const Point<T> &b) {
    return a.x * b.y - a.y * b.x;
}

template<class T>
T cross3(const Point<T> &a, const Point<T> &b, const Point<T> &c) {
    return cross(b - a, c - a);
}

using LD = long double;    
using P = Point<LD>;       
const LD PI = acos(-1);

constexpr LD eps = 0;      

vector<P> convexHull(vector<P> points) {
    int n = points.size();
    if (n <= 1) {
        return points;
    }

    sort(points.begin(), points.end(), [](auto &a, auto &b) {
        if (a.x != b.x) return a.x < b.x;
        return a.y < b.y;
    });
    points.erase(unique(points.begin(), points.end()), points.end());
    n = points.size();

    bool alline = true;
    for (int i = 2; i < n; i++) {
        if (cross(points[1] - points[0], points[i] - points[0]) != 0) {
            alline = false;
            break;
        }
    }
    if (alline) {
        return {points.front(), points.back()};
    }

    vector<P> lower, upper;
    for (const auto &p : points) {
        while (lower.size() >= 2) {
            int m = lower.size();
            P a = lower[m - 2];
            P b = lower[m - 1];
            if (cross(b - a, p - b) <= 0) {
                lower.pop_back();
            } else {
                break;
            }
        }
        lower.push_back(p);
    }
    for (int i = n - 1; i >= 0; i--) {
        auto p = points[i];
        while (upper.size() >= 2) {
            int m = upper.size();
            P a = upper[m - 2];
            P b = upper[m - 1];
            if (cross(b - a, p - b) <= 0) {
                upper.pop_back();
            } else {
                break;
            }
        }
        upper.push_back(p);
    }
    lower.pop_back();
    upper.pop_back();
    lower.insert(lower.end(), upper.begin(), upper.end());
    return lower;
}

void solve() {
    int n;
    cin >> n;

    vector<P> pts(n);
    for (int i = 0; i < n; i++) {
        cin >> pts[i];
    }

    if (n < 4) {
        cout << "0.000\n";
        return;
    }
        
    auto hull = convexHull(pts);

    if (hull.size() <= 2) {
        cout << "0.000\n";
        return;
    }

    if (hull.size() == 3) {
        P A = hull[0], B = hull[1], C = hull[2];
        LD S_tri = fabsl(cross(B - A, C - A)) / 2.0;
        LD delta = 1e300;
        for (auto &p : pts) {
            if (p == A || p == B || p == C) {
                continue;
            }
            LD d1 = fabsl(cross(B - A, p - A)) / 2.0;
            LD d2 = fabsl(cross(C - B, p - B)) / 2.0;
            LD d3 = fabsl(cross(A - C, p - C)) / 2.0;
            delta = min(delta, min({d1, d2, d3}));
        }
        LD ans = (delta < 1e300 ? S_tri - delta : 0.0);
        cout << fixed << setprecision(3) << ans << '\n';
        return;
    }

    int m = hull.size();

    LD ans = 0;
    for (int i = 0; i < m; i++) {
        int a = (i + 1) % m, b = (i + 2) % m;
        for (int j = (i + 1) % m; j != i; j = (j + 1) % m) {
            while (a != j && cross(hull[j] - hull[i], hull[(a + 1) % m] - hull[i]) < cross(hull[j] - hull[i], hull[a] - hull[i])) {
                a = (a + 1) % m;
            }
            while (b != i && cross(hull[j] - hull[i], hull[(b + 1) % m] - hull[i]) > cross(hull[j] - hull[i], hull[b] - hull[i])) {
                b = (b + 1) % m;
            }
            ans = max<LD>(ans, -cross(hull[j] - hull[i], hull[a] - hull[i]) + cross(hull[j] - hull[i], hull[b] - hull[i]));
        }
    }

    cout << fixed << setprecision(3) << ans / 2.0 << '\n';
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t = 1;
    // cin >> t;

    while(t--){
        solve();
    }

    return 0;
}
posted @ 2025-07-26 16:25  カガリ  阅读(8)  评论(0)    收藏  举报