- •Глава 4
- •4.1. Комбинаторные вычисления на конечных множествах
- •4.1.2. Асимптотика
- •Говорят, что при Xx0 f(X) растёт медленнее, чем g(X), или что f(X) "есть о-малое" от g(X).
- •Отсюда, в частности, имеем при n
- •4.1.3. Рекуррентные соотношения
- •Последовательность Фибоначчи асимптотически растёт как
- •4.1.4. Производящие функции
- •4.2. Оценки сложности алгоритмов
- •4.3. Методы повышения эффективности алгоритмов
- •4.3.1. Рекурсия
- •4.3.2. Приём “разделяй и властвуй”
- •4.3.3 Принцип балансировки
- •4.3.4. Динамическое программирование
- •4.3.5. Алгоритмы с возвратом
- •Понимание постановки задачи
- •Составление плана решения
- •Взгляд назад
- •Основные этапы полного построения алгоритма
- •Постановка задачи
- •Временная сложность t(n)
- •Ёмкостная сложность е(n)
- •Заключение
- •Контрольные вопросы. Упражнения
4.3.4. Динамическое программирование
Рекурсивная техника полезна, если задачу можно разбить на подзадачи за разумное время, а суммарный размер подзадач будет небольшим. Из теоремы 4.1 вытекает, что если сумма размеров подзадач равна an для некоторой постоянной а>0, то рекурсивный алгоритм, вероятно, имеет полиномиальную временную сложность. Но если очевидное разбиение задачи размера n сводит её к n задачам размера n-1, то рекурсивный алгоритм, вероятно, имеет экспоненциальную сложность.
В этом случае часто можно получить более эффективные алгоритмы с помощью табличной техники, называемой динамическим программированием.
В сущности, при динамическом программировании вычисляется решение для всех подзадач. Вычисление идет от малых подзадач к большим, и ответы запоминаются в таблице. Преимущество этого метода состоит в том, что раз уж задача решена, её ответ где-то хранится и никогда не вычисляется заново.
Рассмотрим эту технику на примере вычисления произведения k матриц М=М1 x М2 x...x Мk , где Mi - матрица с ri-1 строками и ri столбцами. Порядок, в котором эти матрицы перемножаются, может существенно сказаться на общем числе операций, требуемых для вычисления М, независимо от алгоритма, применяемого для умножения матриц.
Пример 4.1. Будем считать, что умножение (р xq)-матрицы на (q x r)-матрицу требует pqr операций, и рассмотрим произведение (в квадратных скобках указаны размерности матриц).
М= М1 x М2 x М3 x М4
[10 x 20] [20 x 50] [50 x 1] [1 x 100]
Если вычислять М в порядке М1x(М2x(М3xМ4)), то потребуется 125000 операций, тогда как вычисления в порядке (М1x(М2xМ3))xМ4 занимают лишь 2200 операций.
Процесс перебора всех порядков, в которых можно вычислить рассматриваемое произведение n матриц с целью минимизации числа операций, имеет экспоненциальную сложность, что при больших n практически неприемлемо. Однако динамическое программирование приводит к алгоритму сложности О(n3).
4.3.5. Алгоритмы с возвратом
Особенно интересный раздел программирования - это задачи из области “искусственного интеллекта”. Здесь нужно строить алгоритмы, которые находят решение определённой задачи не по фиксированным правилам вычисления, а методом проб и ошибок. Обычно процесс проб и ошибок разделяется на отдельные подзадачи. Часто эти подзадачи наиболее естественно описываются с помощью рекурсии. Процесс проб и ошибок можно рассматривать в общем виде как процесс поиска, который постепенно строит и просматривает (а также обрезает) дерево подзадач. Во многих случаях такие деревья поиска растут очень быстро, обычно экспоненциально, в зависимости от заданного параметра. Соответственно увеличивается стоимость поиска. Часто дерево поиска можно обрезать, используя только эвристические соображения, и тем самым сводить количество вычислений к разумным пределам.
Далее на примере задачи о ходе коня рассматривается общий принцип разбиения таких задач на подзадачи и использование в них рекурсии.
Задача “Обход конем шахматной доски nxn”. Конь помещается на поле с начальными координатами Х0, У0. Нужно покрыть ходами коня всю доску (осуществить обход доски) за n2-1 ход, при том, что каждое поле посещается ровно один раз.
Эта задача покрытия n2 полей сводится к более простой: или выполнить очередной ход, или установить, что никакой ход невозможен.
Характерная черта этого алгоритма состоит в том, что он предпринимает какие-то шаги по направлению к общему решению, эти шаги фиксируются (записываются), но можно возвращаться обратно и стирать записи, если оказывается, что шаг не приводит к решению, а заводит в “тупик”. Такое действие называется возвратом.
Пусть число возможных дальнейших путей на каждом шаге конечно и фиксировано (например, равно m); пусть используется явный параметр уровня, обозначающий глубину рекурсии и допускающий простое условие окончания. Тогда схема, типичная для задач подобного рода, может быть представлена так:
procedure try (i)
begin k := 0; (*инициировать выборку возможных шагов*)
repeat k := k+1; выбрать k-й возможный путь;
if приемлемо then
begin записать его;
if i < n then (*решение неполно*)
begin try (I+1); (*попробовать очередной шаг*)
if неудачно then стереть запись
end
end
until удачно (k=m)
end.
4.4. Построение и анализ алгоритма
4.4.1. Как разрабатывать алгоритм?
Авторы алгоритмов редко раскрывают тайны своего творчества – они или не считают нужным тратить на это время, или не задумываются над этим; можно только догадываться о том, как они пришли к идеям своих алгоритмов. Это общая ситуация, характерная для решения любой проблемы.
Однако всегда находились математики (и представители других наук), для которых вопрос: «Как сформировалась идея?» и более общий вопрос: «Как вообще формировать идеи решения или изобретения?» был важнее решения конкретной задачи (проблемы). Многие выдающиеся математики пытались сформулировать принципы и методы решения любой задачи. Среди них первым можно отметить знаменитого греческого математика Паппа, который жил предположительно около 300 г. н. э. В седьмом томе своего "Математического сборника" он говорит об отрасли науки, названной им эвристикой, так (в свободном изложении): "То, что называют эвристикой, можно кратко определить как особое собрание принципов, предназначенное для тех, кто после изучения «Начал» Евклида имеет желание научиться решать математические задачи…".
Эвристика – не совсем чётко очерченная область науки, которая находится на стыке логики, искусственного интеллекта, философии и психологии. Цель эвристики – исследовать методы и правила, как делать открытия и изобретения. Отдельные высказывания о таком исследовании можно уже обнаружить у комментаторов Евклида.
Наиболее известные попытки создать стройную систему эвристики принадлежат Р. Декарту (1596 – 1650) и Г. Лейбницу (1646 – 1716) - двум великим математикам и философам. Первый попытался разработать универсальный метод решения задач, однако его «Правила для направления ума» остались неоконченными. Второй намеревался написать «Искусство изобретения», но не осуществил своего намерения; однако многочисленные отрывки, разбросанные в его трудах, показывают, что у него были интересные мысли по этому вопросу. Он неоднократно подчеркивал значение этого вопроса; так, он писал: «Нет ничего важнее, чем умение найти источник изобретения, – на мой взгляд, это еще интереснее, чем само изобретение».
Б. Больцано (1781 – 1848), логик и математик, оставил интересное и подробное изложение эвристики; он предпослал изложению введение, в котором написал: «… я приложу усилия к тому, чтобы ясно изложить правила и способы исследования, которыми руководствуются все способные люди …».
Следующим в этом ряду назовём Д. Пойа, не столько великого математика, сколько очень талантливого Учителя. Он написал книгу «Как решать задачу?» [14], весьма полезную как учителю, так и ученику не только средней, но и студенту высшей школы (в последнем случае рекомендуем также познакомиться со второй его книгой [15]). По её мотивам написаны книги [2] и [16].
Задача построения алгоритма, как и любая задача, может быть решена в соответствии с методикой, разработанной Д. Пойа [14]. Она заключается в разбиении процесса решения на этапы:
постановка задачи (понимание постановки задачи);
составление плана решения (анализ);
реализация плана (синтез);
осмысление полученного решения («взгляд назад»)
и в системе чётко сформулированных вопросов к каждому из перечисленных этапов. Назначение вопросов – стимуляция умственной деятельности. В приложении В приведена таблица, заимствованная из [14], в которой к каждому этапу процесса решения даются вопросы и советы, цель которых – помочь решить задачу. Приведём краткие замечания к каждому этапу.