Представьте себе группу прямоугольников, нарисованных на плоскости, каждый прямоугольник с вершинами в целочисленных координатах и сторонами, параллельными осям:
Прямоугольники разбивают плоскость на несколько непересекающихся областей, выделенных красным и синим цветом ниже:
Ваша цель - найти количество таких областей, которые являются идеальными квадратами. В приведенном выше примере их три:
Обратите внимание, что большой квадрат в середине не считается, поскольку он не является отдельной областью, а вместо этого состоит из нескольких меньших непересекающихся областей.
вход
Вы можете написать функцию или полную программу для этой задачи.
Входные данные будут 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
Два больших прямоугольника, которые перекрываются.
Python 2,
480 436 386352 байтаПринимает список пар координат через STDIN в формате:
и печатает результат в STDOUT.
Фактическая программа после замены строки:
объяснение
Вместо того, чтобы возиться со сложными полигонами, эта программа работает с простыми отрезками. Для каждого входного прямоугольника мы добавляем каждое из четырех ребер в список коллективных сегментов по отдельности. Добавление сегмента в список происходит следующим образом: мы тестируем каждый из существующих сегментов на предмет пересечения с новым сегментом; если мы находим пересечение, мы разделяем оба отрезка в точке пересечения и продолжаем. Чтобы упростить задачу, мы фактически ведем два отдельных списка сегментов: горизонтальный и вертикальный. Поскольку сегменты не перекрываются, горизонтальные сегменты могут пересекать только вертикальные сегменты и наоборот. Более того, это означает, что все пересечения (не считая ребер одного и того же прямоугольника) являются «правильными», т. Е. У нас нет Т-образных пересечений, поэтому «обе стороны» каждого сегмента действительно разделены.
Как только мы создали список (ы) сегментов, мы начинаем считать квадраты. Для каждой комбинации из четырех сегментов (в частности, двух горизонтальных и двух вертикальных сегментов) мы проверяем, образуют ли они квадрат. Кроме того, мы проверяем, что в этом квадрате нет вершины (что может произойти, если, например, у нас есть маленький квадрат внутри большего). Это дает нам желаемое количество. Обратите внимание, что, хотя программа проверяет каждую комбинацию четыре раза в разных порядках, конкретное упорядочение координат сегмента гарантирует, что мы будем считать каждый квадрат только один раз.
источник
itertools
для петель, но в итоге оказалось больше. Я могу побрить несколько байтов с помощьюexec
+ замены строк, но ничего особенного.Haskell,
276 266 250 237 225 222217 байтЭто становится все короче ... и более запутанным.
Оцените
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
, в то время как внутренняя часть координаты нет. Количество положительных экземпляров поиска является выходным.источник