【题 解】 CF1025F Triángulos disjuntos

Título

Portal .

Dados algunos puntos en el plano, seleccione 6 puntos de ellos para formar dos triángulos, encuentre el número de soluciones que hacen que los dos triángulos se separen (es decir, no hay ningún punto en el plano que pertenezca a dos triángulos al mismo tiempo), si el punto seleccionado Los mismos triángulos pero diferentes se consideran soluciones diferentes.

análisis

Primero, hay una conclusión: si dos triángulos no se cruzan, entonces debe haber dos tangentes comunes internas. Como se muestra a continuación (comprenda perceptivamente):

VJur90.png

Entonces podemos enumerar la tangente común interna.

Para cada punto de entrada, lo dejamos y otros n - 1 n-1norte-Un punto forma una línea recta y ordena los ángulos polares y luego enumera estas líneas rectas en sentido antihorario mientras se mantiene el número de puntos en el lado derecho de la línea recta. Para cada línea recta, se utiliza el principio de multiplicación para calcular el esquema.

Hay algunos pequeños detalles: cada línea recta puede formar dos triángulos. Como se muestra en la figura anterior, la línea recta CE CEC E puede formar△ ABC \ triangle ABCA B C y△ DEF \ triangle DEFD E F , también puede formar△ ABE \ triangle ABEA B E y△ CDF \ triángulo CDFC D F .. Entonces, cada vez que calcule, debe multiplicar2 22 . Pero cada triángulo se calculará mediante dos líneas rectas al mismo tiempo, por lo que la respuesta final debe dividirse nuevamente a la mitad, que en realidad estará completamente compensada.

Al mismo tiempo, solo enumeramos ángulos polares menores que 0 0Una línea recta de 0 evita una gran colinealidad.

Código

#include <bits/stdc++.h>
#define ll long long
#define MAX 2005
using namespace std;

const double PI = acos(-1.0);

struct vec{
    
    
    double x, y;
}a[MAX];

int n;
double b[MAX];
ll ans;

ll C2(ll x){
    
    
    return (x-1)*x/2;
}

int main()
{
    
    
    cin >> n;
    for (int i = 1; i <= n; ++i) {
    
    
        scanf("%lf%lf", &a[i].x, &a[i].y);
    }
    
    for (int i = 1; i <= n; ++i) {
    
    
        int cnt = 0;
        for (int j = 1; j <= n; ++j) {
    
    
            if(i != j){
    
    
                b[++cnt] = atan2(a[j].y-a[i].y, a[j].x-a[i].x);
            }
        }
        sort(b+1, b+cnt+1);
        for (int j = 1, k = 1; j <= cnt && b[j] <= 0; ++j) {
    
    
            while(k <= cnt && b[k]-b[j] < PI){
    
    		//在直线右侧。
                k++;
            }
            ll l = k-j-1, r = cnt-l-1;		//注意一下点的个数细节:当前点和当前k不能算
            ans += C2(l)*C2(r);		//乘法原理
        }
    }
    
    cout << ans << endl;

    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/qq_30115697/article/details/90749694
Recomendado
Clasificación