Квадратний пошук - Розташування регулярних тетрагонів


27

Уявіть купу прямокутників, намальованих у площині, кожен прямокутник з його вершинами за цілими координатами та його сторонами, паралельними осям:

введіть тут опис зображення

Прямокутники розділяють площину на ряд ділянок, що перетинаються, кольором червоного та синього внизу:

введіть тут опис зображення

Ваша мета - знайти кількість таких регіонів, які є ідеальними квадратами. У наведеному вище прикладі є три:

введіть тут опис зображення

Зауважте, що велика площа в середині не зараховується, оскільки вона не є однією областю, а натомість складається з кількох менших непересічних областей.

Вхідні дані

Ви можете написати функцію або повну програму для цього завдання.

Вхідними будуть 4nневід’ємні цілі числа, що визначають nпрямокутники в площині. Кожен прямокутник представлений двома протилежними вершинами, наприклад, 4 9 7 8являє собою прямокутник з протилежними вершинами (4, 9)і (7, 8). Зауважте, що цей прямокутник також може бути представлений як 7 8 4 9або 4 8 7 9.

Точний формат введення є гнучким (наприклад, розділений пробілом рядок, відокремлений комами рядок, одиночний масив цілих чисел, список кортежів координат тощо), але будь ласка, будьте розумні і наведіть приклад того, як запустити свій код у своїй публікації. Ви не можете змінити порядок введення.

Для простоти можна припустити, що жодне два ребра не буде перекриватися - це включає перекриття у вершині. Зокрема, це означає, що жоден два прямокутники не буде торкатися край-край або кут-кут, а прямокутники матимуть ненульову площу.

Вихідні дані

Ваша програма повинна надрукувати або повернути єдине ціле число, яке є кількістю квадратних областей.

Оцінка балів

Це код гольфу, тому виграє код у найменших байтах.


Тестові справи

Вхід:

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

Вихід:

4

Це просто чотири розрізнені квадрати:

введіть тут опис зображення


Вхід:

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

Вихід:

3

Це приклад тестового випадку на початку публікації.


Вхід:

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

Вихід:

7

введіть тут опис зображення


Вхід:

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

Вихід:

14

введіть тут опис зображення


Вхід:

0 99999 100000 0

Вихід:

0

Це лише один великий прямокутник.


Вхід:

0 99999 100000 0
2 1 142857 285714

Вихід:

1

Два великих прямокутника, які перекриваються.

Відповіді:


9

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

Це запит щодо розширення PostGIS до PostgreSQL. Я не рахував вхідних значень у загальній кількості.

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

Пояснення

Запит будує геометрії для кожної пари координат. Об’єднайте зовнішні кільця, щоб правильно закріпити лінії. Перетворює результати на багатокутники і тестує ширину на висоту та площу, подвоєну проти суми кожної сторони у квадраті.

Він працюватиме як окремий запит на будь-якій базі даних PostgreSQL з розширенням PostGIS.

Редагувати Знайдено ще пару.


1
... і Haskell
оптимізатор

@optimizer Я сумніваюся, це триватиме :)
MickyT

@MickyT Це перетворилося на здорову конкуренцію. :)
Згарб

@zgarb у нього є трохи :-), але я не думаю, що мені ще щось потрібно піти.
MickyT

13

Пітон 2, 480 436 386 352 байти

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 "})

Знімає список пар координат через STDIN у форматі:

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

і друкує результат на STDOUT.


Фактична програма після заміни рядка:

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)

Пояснення

Замість того, щоб сповзати зі складними багатокутниками, ця програма займається простими сегментами ліній. Для кожного вхідного прямокутника ми додаємо кожен його чотири ребра до колективного списку сегментів окремо. Додавання сегмента до списку відбувається наступним чином: ми перевіряємо кожен з існуючих сегментів на перетин з новим сегментом; якщо ми знайдемо перехрестя, розділимо обидва відрізки в точці перетину і продовжимо. Щоб полегшити ситуацію, ми фактично зберігаємо два окремі списки сегментів: горизонтальний та вертикальний. Оскільки сегменти не перетинаються, горизонтальні сегменти можуть перетинатися лише вертикальними сегментами і навпаки. А ще краще, це означає, що всі перетини (не враховуючи ребра одного і того ж прямокутника) "належні", тобто у нас немає Т-подібних перетинів, тому "обидві сторони" кожного відрізка справді розділені.

Після того як ми побудували список сегментів, ми починаємо рахувати квадрати. Для кожної комбінації чотирьох сегментів (зокрема, двох горизонтальних сегментів та двох вертикальних) ми перевіряємо, чи вони утворюють квадрат. Крім того, ми перевіряємо, що в цьому квадраті немає вершини (що може статися, якщо, наприклад, у нас є невеликий квадрат всередині більшого.) Це дає нам бажану кількість. Зауважте, що хоча програма перевіряє кожну комбінацію чотири рази в різних порядках, певне впорядкування координат сегмента гарантує, що ми рахуємо кожен квадрат лише один раз.


1
Я дуже вражений тим, як швидко ти вирішив це і як ти підійшов до проблеми!
Цикли

@ Sp3000 Так. Я спробував використовувати itertoolsпетлі, але в кінцевому підсумку це було довше. Я можу поголити кілька байтів із exec+ замінниками рядків, але нічого надто захоплюючого.
Ell

4

Haskell, 276 266 250 237 225 222 217 байт

Це стає все коротшим ... і більш затуманеним.

(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]])[[],[]]

Оцініть n [(0,0,5,5),(6,8,10,4),(14,16,11,13),(19,1,18,2)]для першого тестового випадку. Я думаю, що я наближаюся до меж гольфу цього алгоритму на Haskell.

Ця функція настільки повільна (принаймні, O (n 3 ), де n - загальний периметр усіх прямокутників на вході), що я не можу оцінити її на двох останніх тестових випадках. Коли я склав його з увімкненими оптимізаціями та запустив його в 400-кратній скороченій версії [(0,249,250,0),(2,1,357,714)]останнього тесту, він закінчився трохи більше 12 секунд. Виходячи з цього, фактичний тестовий випуск закінчиться приблизно через 25 років.

Пояснення (часткове, я розширю це, коли матиму час)

Спочатку будуємо два списки hі vнаступним чином. Для кожного прямокутника на вході ми розділимо його межу на відрізки довжини 1. Західні кінцеві точки горизонтальних відрізків зберігаються в h, а південні кінцеві точки вертикальних відрізків у v, як списки [x,y]довжини 2. Координати в vзберігаються у зворотному напрямку Форма, як [y,x]з міркувань гольфу. Тоді ми просто перебираємо в обох списках і пошук горизонтального краю [x,j]і вертикального краю [i,y]таким чином, що x < iі i-x == j-y(тому вони на північно - заході і південному - кути квадрата), і перевірити , що кордони квадрата знаходяться в правильних списках hі v, в той час як інтер'єр координати немає. Кількість позитивних екземплярів пошуку - вихід.


Молодці, я думаю, мені доведеться поступитися зараз :)
MickyT

@MickyT Минув тиждень, тому я вже прийняв відповідь Згарба, але якщо вам вдасться перемогти її пізніше, галочка може зрушитися! Чесно кажучи, я дуже вражений тим, як далеко вам двом вдалося пройти
Sp3000

@ Zgarb заслужено виграв :-)
MickyT

@ Sp3000 дякую за приємний маленький виклик.
MickyT

@ Sp3000 Дякую! Мені це було дуже весело з гольфу.
Згарб
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.