Squarefinder - Localización de tetragones regulares

27

Imagine un grupo de rectángulos dibujados en el plano, cada rectángulo con sus vértices en coordenadas enteras y sus lados paralelos a los ejes:

ingrese la descripción de la imagen aquí

Los rectángulos dividen el plano en varias regiones disjuntas, de color rojo y azul a continuación:

ingrese la descripción de la imagen aquí

Su objetivo es encontrar el número de tales regiones que son cuadrados perfectos. En el ejemplo anterior, hay tres:

ingrese la descripción de la imagen aquí

Tenga en cuenta que el gran cuadrado en el medio no se cuenta, ya que no es una sola región, sino que se compone de varias regiones disjuntas más pequeñas.

Entrada

Puede escribir una función o un programa completo para este desafío.

La entrada será 4nenteros no negativos que definirán nrectángulos en el plano. Cada rectángulo está representado por dos vértices opuestos, por ejemplo, 4 9 7 8representa el rectángulo con vértices opuestos (4, 9)y (7, 8). Tenga en cuenta que este rectángulo también se puede representar como 7 8 4 9o 4 8 7 9.

El formato de entrada exacto es flexible (por ejemplo, cadena separada por espacios, cadena separada por comas, matriz única de enteros, lista de tuplas de coordenadas, etc.), pero sea ​​razonable y dé un ejemplo de cómo ejecutar su código en su publicación. No puede reordenar la entrada.

Para simplificar, puede suponer que no se superpondrán dos bordes, esto incluye la superposición en un vértice. En particular, esto implica que no habrá dos rectángulos que se toquen de borde a borde o de esquina a esquina, y los rectángulos tendrán un área distinta de cero.

Salida

Su programa debe imprimir o devolver un número entero único, que es el número de regiones cuadradas.

Tanteo

Este es el código de golf, por lo que gana el código en la menor cantidad de bytes.


Casos de prueba

Entrada:

0 0 5 5
6 8 10 4
14 16 11 13
19 1 18 2

Salida:

4

Esto es simplemente cuatro cuadrados disjuntos:

ingrese la descripción de la imagen aquí


Entrada:

2 1 3 11
1 10 5 19
6 10 11 3
8 8 15 15
13 13 9 5
15 1 19 7
17 19 19 17

Salida:

3

Este es el caso de prueba de ejemplo al comienzo de la publicación.


Entrada:

0 9 15 12
6 3 18 15
9 6 12 20
13 4 17 8

Salida:

7

ingrese la descripción de la imagen aquí


Entrada:

5 9 11 10
5 12 11 13
6 8 7 14
9 8 10 14
13 8 14 9
13 10 14 14

Salida:

14

ingrese la descripción de la imagen aquí


Entrada:

0 99999 100000 0

Salida:

0

Este es solo un gran rectángulo.


Entrada:

0 99999 100000 0
2 1 142857 285714

Salida:

1

Dos grandes rectángulos que se superponen.

Sp3000
fuente

Respuestas:

9

SQL (POSTGIS), 286 269 261 240 226 218 216

Esta es una consulta para la extensión PostGIS a PostgreSQL. No he contado los valores de entrada en el total.

SELECT SUM(1)FROM(SELECT(ST_Dump(ST_Polygonize(g))).geom d FROM(SELECT ST_Union(ST_Boundary(ST_MakeEnvelope(a,b,c,d)))g FROM(VALUES
-- Coordinate input
(2, 1, 3, 11)
,(1, 10, 5, 19)
,(6, 10, 11, 3)
,(8, 8, 15, 15)
,(13, 13, 9, 5)
,(15, 1, 19, 7)
,(17, 19, 19, 17)
)i(a,b,c,d))i)a WHERE(ST_XMax(d)-ST_XMin(d))^2+(ST_YMax(d)-ST_YMin(d))^2=ST_Area(d)*2

Explicación

La consulta crea geometrías para cada par de coordenadas. Une los anillos exteriores para agrupar correctamente las líneas. Convierte los resultados en polígonos y pruebas. el ancho contra la altura y el área duplicada contra la suma de cada lado al cuadrado.

Se ejecutará como una consulta independiente en cualquier base de datos PostgreSQL con la Extensión PostGIS.

Editar Encontré un par más.

MickyT
fuente
1
... y Haskell
Optimizer
@optimizer Dudo que dure :)
MickyT
@MickyT Esto se ha convertido en una competencia saludable. :)
Zgarb
@zgarb tiene un poco :-) pero no creo que me quede nada más.
MickyT
13

Python 2, 480 436 386 352 bytes

exec u"""s=sorted;H=[];V=[]
FRIinput():
 S=2*map(s,zip(*R))
 FiI0,1,2,3:
    c=S[i][i/2];a,b=S[~i]
    FeIs(H):
     C,(A,B)=e
     if a<C<b&A<c<B:e[:]=C,(A,c);H+=[C,(c,B)],;V+=[c,(a,C)],;a=C
    V+=[c,(a,b)],;H,V=V,H
print sum(a==A==(d,D)&c==C==(b,B)&B-b==D-d&1-any(d<X[0]<D&b<y<B Fy,XIH)Fb,aIH FB,AIH Fd,cIV FD,CIV)""".translate({70:u"for ",73:u" in ",38:u" and "})

Toma una lista de pares de coordenadas a través de STDIN en el formato:

[  [(x, y), (x, y)],  [(x, y), (x, y)],  ...  ]

e imprime el resultado en STDOUT.


El programa real, después del reemplazo de la cadena, es:

s=sorted;H=[];V=[]
for R in input():
 S=2*map(s,zip(*R))
 for i in 0,1,2,3:
    c=S[i][i/2];a,b=S[~i]
    for e in s(H):
     C,(A,B)=e
     if a<C<b and A<c<B:e[:]=C,(A,c);H+=[C,(c,B)],;V+=[c,(a,C)],;a=C
    V+=[c,(a,b)],;H,V=V,H
print sum(a==A==(d,D) and c==C==(b,B) and B-b==D-d and 1-any(d<X[0]<D and b<y<B for y,X in H)for b,a in H for B,A in H for d,c in V for D,C in V)

Explicación

En lugar de jugar con polígonos complejos, este programa trata con segmentos de línea simples. Para cada rectángulo de entrada, agregamos cada uno de sus cuatro bordes a una lista de segmentos colectivos, individualmente. Agregar un segmento a la lista es el siguiente: probamos cada uno de los segmentos existentes para la intersección con el nuevo segmento; Si encontramos una intersección, dividimos ambos segmentos en el punto de intersección y continuamos. Para facilitar las cosas, en realidad mantenemos dos listas de segmentos separadas: una horizontal y una vertical. Como los segmentos no se superponen, los segmentos horizontales solo pueden intersecar segmentos verticales y viceversa. Mejor aún, significa que todas las intersecciones (sin considerar los bordes del mismo rectángulo) son "apropiadas", es decir, no tenemos intersecciones en forma de T, por lo que "ambos lados" de cada segmento están realmente divididos.

Una vez que hemos construido la (s) lista (s) de segmentos, comenzamos a contar cuadrados. Para cada combinación de cuatro segmentos (particularmente, dos segmentos horizontales y dos verticales), probamos si forman un cuadrado. Además, verificamos que no hay vértices dentro de este cuadrado (lo que puede suceder si, por ejemplo, tenemos un cuadrado pequeño dentro de uno más grande). Esto nos da la cantidad deseada. Tenga en cuenta que aunque el programa prueba cada combinación cuatro veces en diferentes órdenes, el orden particular de las coordenadas del segmento garantiza que contamos cada cuadrado solo una vez.

Ana
fuente
1
¡Estoy bastante impresionado por lo rápido que resolvió esto y la forma en que abordó el problema! Los bucles for me hacen ir "seguramente algo se puede hacer ..."
Sp3000
@ Sp3000 Sí. Intenté usarlo itertoolspara los bucles pero terminó siendo más largo. Puedo reducir algunos bytes con execreemplazos de cadena +, pero nada demasiado emocionante.
Ell
4

Haskell, 276 266 250 237 225 222 217 bytes

Se vuelve cada vez más corto ... y más ofuscado.

(x#i)l=mapM id[[min x i..max x i-1],l]
(y!j)l f=and[p l==p(f[y,j])|p<-map elem$f[y..j]]
s[h,v]=sum[1|[x,j]<-h,[y,i]<-v,x<i,i-x==j-y,(y!j)h$x#i,(x!i)v$y#j]
n=s.foldr(\(x,y,i,j)->zipWith(++)[x#i$[y,j],y#j$[x,i]])[[],[]]

Evaluar n [(0,0,5,5),(6,8,10,4),(14,16,11,13),(19,1,18,2)]para el primer caso de prueba. Creo que me estoy acercando a los límites del golf de este algoritmo en Haskell.

Esta función es tan lenta (al menos O (n 3 ) donde n es el perímetro total de todos los rectángulos en la entrada) que no puedo evaluarla en los últimos dos casos de prueba. Cuando lo compilé con las optimizaciones activadas y lo ejecuté en la versión 400 veces reducida [(0,249,250,0),(2,1,357,714)]de la última prueba, terminó en poco más de 12 segundos. En base a esto, el caso de prueba real terminaría en unos 25 años.

Explicación (parcial, expandiré esto cuando tenga tiempo)

Primero construimos dos listas hy de la vsiguiente manera. Para cada rectángulo en la entrada, dividimos su borde en segmentos de longitud 1. Los puntos finales oeste de los segmentos horizontales se almacenan en h, y los puntos extremos sur de los segmentos verticales en v, como listas [x,y]de longitud 2. Las coordenadas vse almacenan en un reverso forma como [y,x]por razones de golf. Luego, recorremos ambas listas y buscamos el borde horizontal [x,j]y el borde vertical de [i,y]manera que x < iy i-x == j-y(de modo que sean las esquinas noroeste y sureste de un cuadrado), y verifiquemos que los bordes del cuadrado estén en las listas correctas hy v, mientras que el interior las coordenadas no lo son. El número de instancias positivas de la búsqueda es la salida.

Zgarb
fuente
Bien hecho, creo que tendré que ceder ahora :)
MickyT
@MickyT Ha pasado una semana, así que he aceptado la respuesta de Zgarb por ahora, ¡pero si logras superarla más tarde, la marca de verificación podría moverse! Honestamente, estoy muy impresionado por lo lejos que lograron llegar
Sp3000
@ Zgarb mereció ganar :-)
MickyT
@ Sp3000 gracias por un pequeño desafío agradable.
MickyT
@ Sp3000 Gracias! Me divertí mucho jugando al golf.
Zgarb