¡Aquí hay un rompecabezas de geometría engañosamente desafiante para ti!
Dado un círculo A
y n
otros círculos B[n]
, encuentre el área total contenida dentro de la A
cual no está dentro de ningún círculo B
.
Su código debe ser lo más corto posible.
Entrada
Su entrada debe contener la siguiente información:
- Un número de coma flotante para representar el radio del círculo
A
. - Una lista de números de coma flotante para representar los radios de los círculos
B
. - Una lista de los centros de círculos en
B
. Su programa puede esperar los centros en coordenadas polares o cartesianas. - Opcionalmente, puede recibir el número
n
de círculos en B. Esta entrada no es necesaria.
Se supondrá que el centro del círculo A
es el origen, es decir, el punto (0, 0)
.
Se garantiza que no hay dos círculos en B
son idénticos, pero se no garantiza que: todos los círculos de B
intersecan A
, todos los centros de B
están fuera A
, o no hay dos círculos en B
intersecan entre sí. Asegúrese de que su solución pueda manejar varios casos extremos.
Puede recibir entradas en cualquier orden y en forma de entrada de texto (a través de stdin o el equivalente de su idioma), parámetros de función o argumentos de línea de comandos.
Si elige recibir entrada de texto, debe haber delimitadores ASCII imprimibles de uno o dos caracteres entre las entradas.
Salida
Su programa o función debe generar un único número de punto flotante que represente el área total de A
no dentro de ninguno de los círculos de B
. Sus respuestas deben tener una precisión de al menos tres cifras significativas para todos los casos de prueba.
Se aplican reglas generales de código de golf .
Su solución no debe basarse en puntos de muestreo dentro de los círculos para determinar un área.
Los elementos incorporados que localizan automáticamente las intersecciones de los círculos, encuentran áreas dentro de las intersecciones de los círculos o resuelven este problema de inmediato no están permitidos.
Casos de prueba
En cada imagen, el círculo A
se delinea en azul, con círculos B
en verde y negro lleno. El área que debe devolverse se llena de rojo.
(Un agradecimiento especial a Rainer P. por verificar mis soluciones)
Caso de prueba 1:
A = {x: 0, y: 0, rad: 50}
B[0] = {x: 0, y: 0, rad: 100}
Result: 0.00
Caso de prueba 2:
A = {x: 0, y: 0, rad: 100.000000}
B[0] = {x: 100.000000, y: 0.000000, rad: 50.000000}
B[1] = {x: 30.901699, y: -95.105652, rad: 50.000000}
B[2] = {x: -80.901699, y: -58.778525, rad: 50.000000}
B[3] = {x: -80.901699, y: 58.778525, rad: 50.000000}
B[4] = {x: 30.901699, y: 95.105652, rad: 50.000000}
Result: 1.3878e+04
Caso de prueba 3:
A = {x: 0, y: 0, rad: 138}
B[0] = {x: 100, y: 0, rad: 100}
B[1] = {x: -50, y: -86, rad: 100}
B[2] = {x: -93, y: 135, rad: 50}
Result: 1.8969e+04
Caso de prueba 4:
A = {x: 0, y: 0, rad: 121.593585}
B[0] = {x: 81.000000, y: 107.000000, rad: 59.841457}
B[1] = {x: -152.000000, y: -147.000000, rad: 50.000000}
B[2] = {x: 43.000000, y: -127.000000, rad: 105.118980}
B[3] = {x: 0.000000, y: -72.000000, rad: 57.870545}
B[4] = {x: -97.000000, y: -81.000000, rad: 98.488578}
B[5] = {x: -72.000000, y: 116.000000, rad: 66.468037}
B[6] = {x: 2.000000, y: 51.000000, rad: 50.000000}
Result: 1.1264e+04
Caso de prueba 5:
A = {x: 0, y: 0, rad: 121.605921}
B[0] = {x: 0.000000, y: -293.000000, rad: 250.000000}
B[1] = {x: 0.000000, y: -56.000000, rad: 78.230429}
B[2] = {x: 0.000000, y: -102.000000, rad: 100.000000}
Result: 2.6742e+04
Lectura sugerida:
Fewell, MP "Área de superposición común de tres círculos". Octubre de 2006. Web. http://dspace.dsto.defence.gov.au/dspace/bitstream/1947/4551/4/DSTO-TN-0722.PR.pdf .
fuente
B
contenga otro. Podría valer la pena agregar eso.1.8970e+04
.B[0] - A intersection: 20653.659515
,B[1] - A intersection: 20757.824115
,B[1] - B[0] intersection: 1841.847766
,B[2] - A intersection: 1289.164541
, lo que da18969.69009
como la respuesta.Respuestas:
Python 2, 631 bytes
Los saltos de línea precedidos
\
son de fácil lectura y no se cuentan en la puntuación.Lee la entrada a través de STDIN como una lista de
(center, radius)
pares, dondecenter
hay un número complejo en el formularioX+Yj
. El primer círculo de la lista es un (cuyo centro no tiene que estar en el origen), y el resto de la lista es B . Imprime el resultado en STDOUT.Ejemplo
Explicación
Esta es una variación (más larga y mucho más fea: P) en mi solución al área de Martin Büttner de un desafío de polígono autoinsectable. Utiliza el mismo truco de dividir el problema en partes lo suficientemente pequeñas, para lo cual se vuelve más manejable.
Encontramos los puntos de intersección entre todos los pares de círculos (considerando A y los círculos en B ), y pasamos una línea vertical a través de cada uno de ellos. Además, pasamos todas las líneas verticales tangentes a cualquiera de los círculos. Tiramos todas las líneas que no lo hacen se cruzan Una , por lo que todas las líneas restantes están entre las tangentes izquierdo y derecho de una .
Estamos buscando el área de la intersección de A y la unión de los círculos en B , el área de color rojo oscuro en la ilustración de arriba. Esta es el área que tenemos que restar de A para obtener el resultado.
Entre cada par de líneas verticales consecutivas, esta área se puede dividir en un conjunto de trapecios verticales (o triángulos, o segmentos de línea, como casos especiales de trapecios), con un segmento de arco "en exceso" al lado de cada pata. El hecho de que pasemos tantas líneas verticales como lo hacemos garantiza que el área delimitada no es realmente más complicada que eso, ya que de lo contrario tendría que haber un punto de intersección adicional y, por lo tanto, una línea vertical adicional, entre las dos líneas en pregunta.
Para encontrar estos trapecios y segmentos de arco, para cada par de líneas verticales consecutivas, encontramos los segmentos de arco de cada uno de los círculos que se encuentran correctamente entre estas dos líneas (por supuesto, algunos círculos pueden no tener segmento de arco entre un par de líneas dado .) En la siguiente ilustración, estos son los seis segmentos de arco amarillo (brillante y oscuro), cuando se consideran las dos líneas verticales rojas. Tenga en cuenta que, dado que pasamos todas las líneas verticales tangentes a los círculos, si un círculo tiene un segmento de arco entre las dos líneas, necesariamente intersecta ambas líneas, lo que simplifica el resto del algoritmo.
No todos estos arcos son relevantes; sólo estamos interesados en los que están en el límite de la intersección entre la A y la unión de B . Para encontrarlos, clasificamos los arcos de arriba a abajo (tenga en cuenta que los arcos pueden no cruzarse adecuadamente entre sí, ya que esto implicaría la existencia de otra línea vertical entre los dos que estamos considerando, por lo que tiene sentido hablar sobre un arco arbitrario sobre o debajo de cualquier otro.)
Atravesamos los arcos, en orden, mientras contamos el número de círculos B que estamos dentro, n . Si n cambia de 0 a 1 mientras estamos dentro de A , o si estamos en el arco superior de A mientras n no es cero, entonces el arco actual corresponde a un tramo de un trapecio. Si n cambia de 1 a 0 mientras estamos dentro de A , o si estamos en el arco inferior de A mientras nes distinto de cero, entonces el arco actual corresponde a la otra pata del mismo trapecio. Una vez que encontramos un par tal de arcos (los dos arcos de color amarillo brillante en la ilustración anterior), calculamos el área del trapezoide correspondiente, y de los dos segmentos de arco, y añadirlo a la superficie total se restan de la A .
Calcular el área de A , así como las áreas de los trapecios, es bastante sencillo. El área de cada segmento de arco es el área del sector circular correspondiente, menos el área del triángulo cuyos vértices son los dos puntos finales del segmento de arco y el centro del círculo correspondiente.
fuente