Maior quadrilátero - casco convexo + casco de cartão rotativo

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 ≥ 44 , 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;
}

Acho que você gosta

Origin blog.csdn.net/bloom_er/article/details/109952765
Recomendado
Clasificación