Título
O significado do título desta pergunta é óbvio: dados vários pontos em um plano bidimensional, encontre a área máxima do quadrilátero que pode ser formada por esses pontos.
- A primeira coisa a ser feita é encontrar o casco convexo desses pontos, que é a maior área do quadrilátero nos quadriláteros construídos no casco convexo.
- Depois de formar o casco convexo, existem as seguintes três situações
- O casco convexo final formado é uma linha reta, ou seja, todos os pontos estão em linha reta.O número de pontos do casco convexo formado neste momento é 2, e a área do quadrilátero formado é 0.
- O casco convexo final tem apenas três pontas, e o que será construído neste momento é um quadrilátero côncavo. Em seguida, enumere diretamente os pontos no casco convexo e encontre a área mínima desse ponto e os pontos em dois dos cascos convexos. Finalmente, subtraia a área mínima do triângulo da área do triângulo do casco convexo.
- O número de pontos convexos do casco formados ≥ 4 ≥ 4≥4 , você precisa usar a caixa de cartão rotativa para calcular a área. Primeiro divida o quadrilátero em dois triângulos, depois enumere o primeiro e o terceiro pontos e use a carta rotativa para localizar a maior área do triângulo no estado atual.
- Os dados desta questão têm poços e pontos repetidos. Quando há apenas três pontos correspondentes ao casco convexo, os pontos repetidos podem formar diretamente a maior área do triângulo do casco convexo.
- Veja o código para detalhes
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uii;
typedef pair<int, int> pii;
template<typename T>
inline void rd(T& x)
{
int tmp = 1; char c = getchar(); x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1; c = getchar(); }
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0'; c = getchar(); }
x *= tmp;
}
const int N = 1e5 + 10;
const int M = 1e5 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
int sgn(double x) {
//一个数是否等于0
if (fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct Point {
ll x, y;
Point() {
}
Point(ll x, ll y) :x(x), y(y) {
}
Point operator+(const Point& B) {
return Point(x + B.x, y + B.y); }
Point operator-(const Point& B) {
return Point(x - B.x, y - B.y); }
Point operator*(double k) {
return Point(x * k, y * k); }
Point operator/(double k) {
return Point(x / k, y / k); }
bool operator ==(const Point& B) {
return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; }
bool operator <(const Point& B) {
return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0); }
};
typedef Point Vector;//向量
ll Cross(Vector A, Vector B) {
return A.x * B.y - A.y * B.x; }
int Andrew(Point* p, int n, Point* q) {
//p是原图,q是凸包图
sort(p, p + n, [](const Point& a, const Point& b) {
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
});
n = unique(p, p + n) - p;
int num = 0; //凸包的点数
for (int i = 0; i < n; ++i) {
while (num > 1 && sgn(Cross(q[num - 1] - q[num - 2], p[i] - q[num - 2])) <= 0) --num;
q[num++] = p[i];
}
int tmp = num;
for (int i = n - 2; i >= 0; --i) {
while (num > tmp && sgn(Cross(q[num - 1] - q[num - 2], p[i] - q[num - 2])) <= 0) --num;
q[num++] = p[i];
}
if (n > 1) --num;
return num;
}
inline int nxt(int pos, int n) {
return pos + 1 == n ? 0 : pos + 1;
}
ll RotateCaliper(Point p[], int n) {
ll res = 0;
for (int p1 = 0; p1 < n; ++p1) {
int p2 = nxt(p1, n);
int p4 = nxt(nxt(nxt(p1, n), n), n);
for (int p3 = nxt(p2, n); p3 != p1; p3 = nxt(p3, n)) {
while (nxt(p2, n) != p3 && Cross(p[p2] - p[p1], p[p3] - p[p1]) < Cross(p[nxt(p2, n)] - p[p1], p[p3] - p[p1])) p2 = nxt(p2, n);
if (p4 == p3) p4 = nxt(p4, n);
while (nxt(p4, n) != p1 && Cross(p[p3] - p[p1], p[p4] - p[p1]) < Cross(p[p3] - p[p1], p[nxt(p4, n)] - p[p1])) p4 = nxt(p4, n);
res = max(res, Cross(p[p2] - p[p1], p[p3] - p[p1]) + Cross(p[p3] - p[p1], p[p4] - p[p1]));
}
}
return res;
}
Point p[N], q[N];
int main() {
// FILE* _INPUT = freopen("input.txt", "r", stdin);
//FILE* _OUTPUT = freopen("output.txt", "w", stdout);
int T; rd(T);
while (T--) {
int n; rd(n);
for (int i = 0; i < n; ++i) {
rd(p[i].x); rd(p[i].y);
}
int tmp = n;
n = Andrew(p, n, q);
if (n == 2) {
puts("0");
continue;
}
else if (n == 3) {
ll ans = Cross(q[1] - q[0], q[2] - q[0]);
ll res = 4e18;
int cnt0 = 0, cnt1 = 0, cnt2 = 0;
for (int i = 0; i < tmp; ++i) {
if (p[i] == q[0]) {
++cnt0;
continue;
}
if (p[i] == q[1]) {
++cnt1;
continue;
}
if (p[i] == q[2]) {
++cnt2;
continue;
}
for (int j = 0; j < 3; ++j) {
ll tmp = Cross(q[nxt(j, n)] - q[j], p[i] - q[j]);
if (tmp < 0) continue;
res = min(res, tmp);
}
}
if (cnt0 > 1 || cnt1 > 1 || cnt2 > 1) res = 0;
ans -= res;
if (ans & 1) printf("%lld.5", ans / 2);
else printf("%lld\n", ans / 2);
}
else {
ll ans = RotateCaliper(q, n);
if (ans & 1) printf("%lld.5\n", ans / 2);
else printf("%lld\n", ans / 2);
}
}
return 0;
}