Блог пользователя miraina

Автор miraina, 13 лет назад, По-русски

Как наиболее эффективно и быстро решить эту задачу:

Однажды Дима вышел на улицу погулять. Первым делом он отправился на футбольное поле, но никого там не обнаружил. Его внимание привлекли странные ямки. Как раз этим утром он читал про круги на полях и сразу заподозрил неладное. Более того, он понял, что искать! Он считает, что на поле есть такие четыре ямки, которые являются вершинами квадрата, стороны которого параллельны сторонам поля. Помогите Диме понять, прав ли он.

Входные данные
В первую строку входного файла записано целое число N — количество ямок на поле (1 ≤ N ≤ 2012). Следующие N строк содержат декартовы координаты ямок — пары целых чисел, не превосходящих 1000000 по абсолютной величине. В каждой строке координаты записаны через пробел. Футбольное поле имеет прямоугольную форму. Оси координат параллельны сторонам поля.

Выходные данные
Если Дима прав, выведите в выходной файл через пробел в любом порядке номера ямок, образующих искомый квадрат. Ямки нумеруются с единицы в том порядке, в котором они перечислены во входном файле. Если таких квадратов несколько, выберите любой.
Если квадрата нет, выведите строку NO SOLUTION.

Заранее спасибо за помощь!

  • Проголосовать: нравится
  • +3
  • Проголосовать: не нравится

13 лет назад, # |
  Проголосовать: нравится +1 Проголосовать: не нравится
а как можно хэш функцию для какой-нибудь точки А(х,у) найти? Hash(x,y) = ? и будет ли  Hash(x,y) целым числом?
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Можно.
    Обычно хэш-функция задается от строки, поэтому сделаем кое-какие преобразования.

    T = x+y+x*y;
    S = string(T);
    hash(s);

    Вот и все. Тогда и поиск быстрее получится.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      А если Т получится отрицательным?
      в принципе, если находить так: hash(x,y) = P*x + y, где P=простое число. То коллизий мало будет?
      • 13 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

        Ну и что? Хэш-функция вычисляется от строки, так что ничего страшного в этом нет.

        Если P брать каким-нибудь большим, то будет мало коллизий, но надо брать большой размер хэш-таблицы, но тогда посыпятся ML'и.

        Хотя при подобных ограничениях коллизий много не будет, даже если взять P~200.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Можно еще φ(x, y) = p· x + y(mod q), где p, q - различные простые числа, тогда МЛ меньше шансов словить.
13 лет назад, # |
Rev. 7   Проголосовать: нравится 0 Проголосовать: не нравится

Мутное решение, но правильное.

Сортируем точки по X.
Создаем двумерный массив, в нем храним все точки: в одной строке точки с одинаковым X.
Вложенные циклы: внешним и внутренним идем по всем точкам.
point1 = a[i];
point2 = a[j];
if ((point1.x=point2.x) || (point1.y=point2.y)) continue;
Если значения X и Y координат у этих точек различны, то предполагаем, что это - угловые противоположные точки квадрата.
Теперь вспоминаем, что у нас есть массив, в котором лежат точки, "разложенные" по координатам X.
Бинарным поиском проверяем по соответствующим строкам массива (point1.x и point2.x): есть ли точки point3(point1.x,point2.y) и point4(point2.x,point1.y). 
Если есть, то выводим все 4 точки и выходим из программы, если нет, то идем дальше.
В самом конце выводим "NO SOLUTION" - если бы мы нашли решение, то уже бы вывели его.
В итоге получаем асимптотику O(N2*log2(N)).

P.S. Понятно, что для каждой точки нужно хранить и ее начальный номер, чтобы вывести в конце.

UPD: выше предложено решение с хэш-функцией. Не проверено, но должно работать. Решение работает.
UPD: Ссылка на рабочий код: http://pastebin.com/Z488ALj6
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Можно создать не двумерный массив, а одномерный массив, отсортированный сначала по X, а при равенстве X отсортирован по Y. В таком массиве также можно искать точку бинарным поиском, так будет меньше магии. Асимптотика O().

    Чтобы избавиться от логарифма в асимптотике, можно засунуть все точки в hash-таблицу. Так как поиск элемента в hash-таблицу в среднем примерно O(1), то и асимптотика будет O(N2).
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Когда я писал такое решение (апрель 2011), я о хэш-таблицах не знал.

      Да, с обычной сортировкой магии действительно меньше (:
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Все точки кидаешь в хеш-таблицу. Затем перебираешь две точки, которые будут образовывать диагональ квадрата, осталось проверить есть ли в хеш-таблице оставшиеся две точки.
13 лет назад, # |
Rev. 3   Проголосовать: нравится -8 Проголосовать: не нравится

Можно сжать все координаты (за O(n * log(n)) ) и использовать двумерный массив, перебирая пары точек. Всего пар O(n2), проверка на то, что есть соответствующие точки выполняется за O(1). Сложность алгоритма та же, но не нужно использование хэш таблицы.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Сжать - что вы имеете в виду?
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Общая идея такая: отсортируем все координаты. И перенумеруем их, самая маленькая - это 0, самая большая - N - 1. 
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Чего-то коментарий пропал... :-(
  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Строим хеш от (x,y) [чтобы быстро проверять есть ли такая точка] - O(n)
    Группируем точки по x (или y, в зависимости от того, где менее населенные группы получаются) - O(n)
    Цикл по всем группам
    В пределах группы x рассматриваем все пары (x,y1) и (x,y2), d=y2-y1 и проверяем есть ли точки (x+d,y1) и (x+d,y2).

    если мало точек с одинаковыми x или y, то получается O(n)
    если много точек с одинаковыми x и одновременно много с одинаковыми y, то O(n*n)

    можно немного пооптимизировать. например можно пропустить рассмотрение наиболее населенной группы и т.п.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Спасибо всем, вот только какой-то баг с комментариями - из 27 комментариев показаны лишь 19:(