【计算几何】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;
}

浙公网安备 33010602011771号