Шаг 107.
Рекурсия на Python.
Множественная рекурсия I: "разделяй и властвуй". Задача очертания

    На этом шаге мы рассмотрим общий принцип решения этой задачи.

    Задача очертания заключается в том, чтобы определить контур на фоне неба ряда прямоугольных зданий. Рисунок 1 поясняет задачу.


Рис.1. Задача очертания

    Вход задачи - список из n > 1 прямоугольников, изображающих здания (см. рисунок 1(a)). Нижняя сторона прямоугольников всегда расположена на уровне 0. Таким образом, каждое здание можно определить всего тремя параметрами. В данном случае мы будем использовать кортежи вида 1, x2, h), где х1 - положение левой стены здания, х2 - положение его правой стены, а h - его высота, причём х1 < х2 и h > 0. Например, [(1, 7, 7), (18, 20, 7), (2, 9, 5), (17, 19, 2), (12, 24, 3), (3, 8, 8), (11, 13, 5), (15, 21, 6)]. Отметим, что нет необходимости сортировать здания каким-либо образом (скажем, по значению х1).

    Контур, выделенный жирной линией на рисунке 1(b), - это ломаная линия, высота которой в любой точке оси X является высотой максимально высокого здания в этой точке. Так как здания суть прямоугольники, то их контур можно определить набором координат (х, h) на плоскости, которые задают точки х изменения высоты h, как показано на рисунке 1(c). Таким образом, результат задачи - упорядоченный по возрастанию х список пар координат, которые можно представить кортежами. Для приведённого выше примера результатом будет список [(1, 7), (3, 8), (8, 5), (9, 0), (11, 5), (13, 3), (15, 6), (18, 7), (20, 6), (21, 3), (24, 0)].

    Размер задачи - количество зданий n. Начальному условию соответствует наименьший экземпляр задачи - одно здание. Если оно задано кортежем 1, x2, h), то результатом будет список [(x1, h), (x2, 0)], как показано на рисунке 2.


Рис.2. Начальное условие задачи очертания для одного здания

    Декомпозицию этой задачи можно осуществить уменьшением её размера на 1. Однако это приводит к алгоритму со временем выполнения в худшем случае Ο(n2). Вместо него мы применим подход "разделяй и властвуй", который позволяет решить задачу за время Ο(n log n). Рисунок 3 иллюстрирует эту идею, которая подобна подходу, применённому в алгоритме сортировки слиянием.


Рис.3. Рекурсивное условие задачи очертания

    Шаг декомпозиции заключается в делении входного списка на два меньших подсписка примерно из n/2 зданий. Тогда метод выполняет два рекурсивных вызова с этими подсписками, которые возвращают два независимых контура. Предположив на основании индукции, что контуры были созданы правильно, последним и главным для получения результата шагом будет объединение контуров. В примере 6.14 приводится отвечающий принципу "разделяй и властвуй" метод, структура которого, в сущности, совпадает с таковой в примере 6.2.


Пример 6.14. Основной рекурсивный метод вычисления очертания
1
2
3
4
5
6
7
8
9
def compute_skyline(buildings):
    n = len(buildings)
    if n == 1:
        return ([(buildings[0][0], buildings[0][2]),
                 (buildings[0][1], 0)])
    else:
        skylines1 = compute_skyline(buildings[0:n // 2])
        skylines2 = compute_skyline(buildings[n // 2:n])
        return merge_skylines(skylines1, skylines2, 0, 0)    

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг