【计算几何】Largest Quadrilateral

来源:https://codeforces.com/gym/102460 的L题
这道题和 https://www.luogu.com.cn/problem/P4166 是一样的思路,不过要注意凸包中只有三个点的情况,如果有点和三角形重合,三角形和这个重合的点连起来就是四边形了,此时的最大面积就是三角形的面积。
如果没有,就固定凸包这三个点,去遍历剩余的点,取最小值即可。

#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<int>;       
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();

    if (n <= 1) {
        return points;
    }

    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\n";
        return;
    }
        
    auto hull = convexHull(pts);

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

    if (hull.size() == 3) {
        bool ok = false;
        P A = hull[0], B = hull[1], C = hull[2];
        int cnta = 0, cntb = 0, cntc = 0;
        int S_tri = cross(B - A, C - A);
        int delta = INF;
        for (auto &p : pts) {
            if (p == A || p == B || p == C) {
                if (p == A) {
                    cnta++;
                    if (cnta > 1) {
                        ok = true;
                        break;
                    }
                } else if (p == B) {
                    cntb++;
                    if (cntb > 1) {
                        ok = true;
                        break;
                    }
                } else {
                    cntc++;
                    if (cntc > 1) {
                        ok = true;
                        break;
                    }
                }
                continue;
            }
            int d1 = cross(B - A, p - A);
            int d2 = cross(C - B, p - B);
            int d3 = cross(A - C, p - C);
            delta = min(delta, min({d1, d2, d3}));
        }
        if (ok) {
            if (S_tri & 1) {
                cout << S_tri / 2 << ".5\n";
            } else {
                cout << S_tri / 2 << '\n';
            }
            return;
        } 
        if (delta < (int) INF) {
            int d = S_tri - delta;
            if (d & 1) {
                cout << d / 2 << ".5\n";
            } else {
                cout << d / 2 << '\n';
            }
        } else {
            cout << "0\n";
        }
        return;
    }

    int m = hull.size();    

    int ans = 0;
    for (int i = 0; i < m; i++) {
        int a = (i + 1) % m, b = (i + 2) % m;
        for (int j = (i + 2) % 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(ans, -cross(hull[j] - hull[i], hull[a] - hull[i]) + cross(hull[j] - hull[i], hull[b] - hull[i]));
        }
    }

    if (ans & 1) {
        cout << ans / 2 << ".5" << '\n';
    } else {
        cout << ans / 2 << '\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 19:04  カガリ  阅读(9)  评论(0)    收藏  举报