задачка (программирование)
May. 25th, 2014 06:08 pmМне эта задачка попалась недавно на сайте программистских соревнований, когда я помогал кое-кому готовиться к интервью и искал материал для интересных вопросов. Она мне понравилась тем, что я не смог ее быстро решить.
Комментарии я скрывать не буду - если хотите предложить там свое решение, то пожалуйста, если хотите подумать сами, не заглядывайте туда.
P.S. Я бы сказал, опираясь на собственный опыт, что эта задача несколько сложнее, чем типичная алгоритмическая задача на интервью в Гугле. Если вы можете эту задачу решить и за 45 минут написать работающий код, за разумное время дающий правильный ответ - ваш уровень по крайней мере в алгоритмах вполне подходит и даже превосходит то, что в Гугле просят продемонстрировать на интервью.
Вы - авиадиспетчер, которому нужно посадить N самолетов в аэропорту, у которого только одна посадочная полоса. Про каждый самолет известно окно времени, в которое он может безопасно приземлиться - оно задается в минутах, от 0 до 1440. Например, про один самолет может быть известно, что его можно посадить в любое время от 7-й минуты до 300-й включительно, про другой - в любое время от 100-й до 200-й, и так далее. Предположим, что вы для каждого самолета выбрали время посадки (его можно задать с точностью до секунды). Будет какое-то минимальное временное расстояние между посадками самолетов. Ваша задача -- это минимальное расстояние максимизировать.
На вход вам дается: число самолетов N, от 2 до 8; для каждого самолета начальная и конечная границы окна, от 0 до 1440. На выход вы должны дать: максимальное значение минимального расстояния между посадками, которое вы беретесь обеспечить.
Комментарии я скрывать не буду - если хотите предложить там свое решение, то пожалуйста, если хотите подумать сами, не заглядывайте туда.
P.S. Я бы сказал, опираясь на собственный опыт, что эта задача несколько сложнее, чем типичная алгоритмическая задача на интервью в Гугле. Если вы можете эту задачу решить и за 45 минут написать работающий код, за разумное время дающий правильный ответ - ваш уровень по крайней мере в алгоритмах вполне подходит и даже превосходит то, что в Гугле просят продемонстрировать на интервью.
no subject
Date: 2014-05-25 03:22 pm (UTC)no subject
Date: 2014-05-25 03:30 pm (UTC)no subject
Date: 2014-05-25 03:35 pm (UTC)Вход: (N окон, Start time, End Time)
Для всех самолетов А из N
- выбрать А первым самолетом в расписании посадок
- Назначить ему время посадки T_A - самое раннее из возможных
- Найти такое T', что
(Уравнение 1): (T'-T_A) = FindMaxMinGap(N-1 оставшихся окон, T', End Time)
(если такого нет, то наибольшее T', для которого левая часть меньше правой)
- вернуть (T'-T_A)
Если N=1, вернуть T_E - Start_time, где T_E = самое позднее время посадки данного самолета.
Ключевой момент - поиск T'. Здесь мы замечаем, что FindMaxMinGap - невозрастающая функция от второго параметра (Start Time), поэтому решение уравнения (1) можно провести бинарным поиском - т.е. порядка 16 попыток для 86400 возможных позиций. Итого сложность будет где-то 16^N * (N!).
no subject
Date: 2014-05-25 03:41 pm (UTC)no subject
Date: 2014-05-25 03:48 pm (UTC)первый самолет посадить в минимальную границу, последний - в максимальную.
Остальные самолеты первоначально расположить произвольно. Затем рассчитать попарные расстояния между соседними. понятно, что расстояния между не-соседними можно не принимать во внимание. после этого начать усреднять эти расстояния. В качестве начальной пары можно взять минимальное и усреднить с бОльшим из соседей. Далее цикл повторяется. Если новое значение оказывается за пределами окна для данного самолета - оставить на ближайшей к этому значению границе.
Поннятно, что при таком алгоритме минимальное расстояние не уменьшается, и ограницено сверху значением 1440/(N-1), поэтому имеет предел. Установить порог изменения в 1 секунду, после чего цикл обрывать при изменениях меньше секунды.
Насчет скорости сходимости алгоритма - надо подумать, сходу кажется, что количество операций - полином от N.
no subject
Date: 2014-05-25 03:49 pm (UTC)Делением пополам перебираем размеры минимального расстояния (log(1440/(N-1)).
Пытаемся расставить самолеты с заданным минимальным расстоянием и в заданном порядке (легко сделать за один проход).
Итого: O(N*N!*log(1440/(N-1))) - при ограничении на N <= 8 должно давать разумное время.
no subject
Date: 2014-05-25 03:53 pm (UTC)no subject
Date: 2014-05-25 03:58 pm (UTC)no subject
Date: 2014-05-25 04:24 pm (UTC)Тут явно какие-то end cases по углам прячутся, лень было их искать (на интервью я бы постарался :)), плюс это только non-overlapping case.
А ты свой вариант написал?
no subject
Date: 2014-05-25 04:30 pm (UTC)no subject
Date: 2014-05-25 04:33 pm (UTC)no subject
Date: 2014-05-25 04:35 pm (UTC)no subject
Date: 2014-05-25 04:54 pm (UTC)Суть:
1. сортируем самолеты по началу окна - получаем arr
2. для каждого элемента arr считаем delta_max - max из окна между прилетом arr[i] и arr[i+1]
3. берем минимальное значение из всех delta_max и погнали по массиву arr - для arr[0] берем, конечно же, начало промежутка. для каждого arr[i] если time(arr[i]) попадает в окно времени arr[i+1] - все ок, идем к следующему. если дошли до конца массива и наша delta меньше delta_max, то берем середину между delta и delta_max (с округлением до секунд, конечно же), иначе - делим пополам delta - и так методом бисекции находим искомое время.
и вот тут загвоздка. по идее чтобы учесть все оверлапы нужно так же пройтись с конца массива, вычитая дельту из окончания окна последнего самолета в массиве. и неплохо повторить бы то же самое для массива самолетов, но отсортированных уже по концам окон прилетов...
в принципе время-то конечное, вроде как даже линейное относительно количества самолетов (в оценке сложности алгоритмов не силен)
no subject
Date: 2014-05-25 05:12 pm (UTC)Но это легко лечится - если окна пересекаются, то размножаем самолеты:
в каждой области попарного пересечения - будет два самолета (т.е. в вашем примере - 4 самолета - первый в области 7-8, два самолета в области 8-9 и четвертый самолет в области 9-300).
Решаем задачу, населенную размноженными самолетами, а потом вспоминаем, что некоторые из размноженных - один и тот же - после чего перебираем все варианты его помещения в одно положение из всех, которые занимали его клоны.
После чего решаем все переборы по исходному алгоритму, а из множества полученных вариантов выбираем максимальный.
( в вашем примере, оптимальное положение четырех самолетов - в точках 7,8,9,300, после чего решаем четыре задачи:
нач. первого нач. второго
7 8 - конечное положение 7,9 - расстояние 2
7 9 - конечное положение 7,9 - расстояние 2
8 9 - конечное положение 7,9 - расстояние 2
9 8 - конечное положение 8,300 - расстояние 292
300 8 - конечное положение 8,300 - расстояние 292
300 9 - конечное положение 8,300 - расстояние 292
Ответ - 292)
no subject
Date: 2014-05-25 05:18 pm (UTC)Но вот что с перестановками делать - ума не приложу.
no subject
Date: 2014-05-25 05:20 pm (UTC)no subject
Date: 2014-05-25 05:34 pm (UTC)должно сработать. конечно, при таком алгоритме порядок посадки самолетов не изменится, так что на глобальный оптимум не надеемся. но можно попробовать несколько раз с первыми случайными распределениями (т.е. с разной очередностью).
no subject
Date: 2014-05-25 05:35 pm (UTC)Должен быть проще алгоритм.
no subject
Date: 2014-05-25 05:38 pm (UTC)no subject
Date: 2014-05-25 05:55 pm (UTC)no subject
Date: 2014-05-25 06:30 pm (UTC)Ставим все времена на левые края окон.
Берем 1 самолет и двигаем его по его интервалу - если какое то новое положение 1го самолета дает общий выигрыш, то оставляем его.
Берем 2 самолет и двигаем ...
...
Берем N самолет и двигаем...
И снова берем 1 самолет ...
Продолжать, пока не получим, что ни один из N самолетов нельзя переставить не ухудшив результат.
no subject
Date: 2014-05-25 06:39 pm (UTC)no subject
Date: 2014-05-25 06:41 pm (UTC)no subject
Date: 2014-05-25 06:54 pm (UTC)- Ищем min левых границ и max правых, этот диапазон разбиваем на равные N-1 частей - получаем "идеальные" точки
- Смотрим, диапазоны, не покрывающие ни одной, ищем среди них минимальное расстояние от границы диапазона до одной из точек, сдвигаем её на границу диапазона, отрезки по обе стороны переразбиваем, диапазон и точку убираем из рассмотрения
- Смотрим точки, не покрытые ни одним диапазоном, та же процедура
- Все диапазоны покрывают хотя бы одну точку и каждая покрыта хотя бы одним диапазоном - можно распределить без дальнейших сдвигов времени вылетов - не будем этого делать, просто смотрим минимум, это результат
В каком случае такой подход ломается?
no subject
Date: 2014-05-25 07:00 pm (UTC)