1. Алгоритмы и способы их...

71
1. Алгоритмы и способы их описания Понятие алгоритма Для составления программы, предназначенной для решения на ЭВМ какой- либо задачи, требуется составление алгоритма ее решения. Алгоритм — это точное предписание, которое определяет процесс, ведущий от исходных данных к требуемому конечному результату. Алгоритмами, например, являются правила сложения, умножения, решения алгебраических уравнений, умножения матриц и т.п. Слово алгоритм происходит от algoritmi, являющегося латинской транслитерацией арабского имени хорезмийского математика IX века аль-Хорезми. Благодаря латинскому переводу трактата аль-Хорезми европейцы в XII веке познакомились с позиционной системой счисления, и в средневековой Европе алгоритмом называлась десятичная позиционная система счисления и правила счета в ней. Применительно к ЭВМ алгоритм определяет вычислительный процесс, начинающийся с обработки некоторой совокупности возможных исходных данных и направленный на получение определенных этими исходными данными результатов. Термин вычислительный процесс распространяется и на обработку других видов информации, например, символьной, графической или звуковой. Если вычислительный процесс заканчивается получением результатов, то говорят, что соответствующий алгоритм применим к рассматриваемой совокупности исходных данных и решает поставленную задачу. В противном случае говорят, что алгоритм неприменим к совокупности исходных данных. Любой применимый алгоритм обладает следующими основными свойствами: результативностью; определенностью; массовостью. Результативность означает возможность получения результата после выполнения конечного количества операций. Определенность состоит в совпадении получаемых результатов независимо от пользователя и применяемых технических средств. Массовость заключается в возможности применения алгоритма к целому классу однотипных задач, различающихся конкретными значениями исходных данных. Для задания алгоритма необходимо описать следующие его элементы: набор объектов, составляющих совокупность возможных исходных данных, промежуточных и конечных результатов; правило начала; правило непосредственной переработки информации (описание последовательности действий);

Transcript of 1. Алгоритмы и способы их...

Page 1: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1. Алгоритмы и способы их описания Понятие алгоритма

Для составления программы, предназначенной для решения на ЭВМ какой-

либо задачи, требуется составление алгоритма ее решения.

Алгоритм — это точное предписание, которое определяет процесс,

ведущий от исходных данных к требуемому конечному результату.

Алгоритмами, например, являются правила сложения, умножения, решения

алгебраических уравнений, умножения матриц и т.п. Слово алгоритм

происходит от algoritmi, являющегося латинской транслитерацией арабского

имени хорезмийского математика IX века аль-Хорезми. Благодаря латинскому

переводу трактата аль-Хорезми европейцы в XII веке познакомились с

позиционной системой счисления, и в средневековой Европе алгоритмом

называлась десятичная позиционная система счисления и правила счета в ней.

Применительно к ЭВМ алгоритм определяет вычислительный процесс,

начинающийся с обработки некоторой совокупности возможных исходных

данных и направленный на получение определенных этими исходными

данными результатов. Термин вычислительный процесс распространяется и

на обработку других видов информации, например, символьной, графической

или звуковой.

Если вычислительный процесс заканчивается получением результатов, то

говорят, что соответствующий алгоритм применим к рассматриваемой

совокупности исходных данных и решает поставленную задачу. В противном

случае говорят, что алгоритм неприменим к совокупности исходных данных.

Любой применимый алгоритм обладает следующими основными свойствами:

результативностью;

определенностью;

массовостью.

Результативность означает возможность получения результата после

выполнения конечного количества операций.

Определенность состоит в совпадении получаемых результатов независимо от

пользователя и применяемых технических средств.

Массовость заключается в возможности применения алгоритма к целому

классу однотипных задач, различающихся конкретными значениями исходных

данных.

Для задания алгоритма необходимо описать следующие его элементы:

набор объектов, составляющих совокупность возможных исходных

данных, промежуточных и конечных результатов;

правило начала;

правило непосредственной переработки информации (описание

последовательности действий);

Page 2: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

правило окончания;

правило извлечения результатов.

Алгоритм всегда рассчитан на конкретного исполнителя. В нашем случае таким

исполнителем является ЭВМ. Для обеспечения возможности реализации на

ЭВМ алгоритм должен быть описан на языке, понятном компьютеру, то есть на

языке программирования.

Таким образом, можно дать следующее определение программы.

Программа для ЭВМ представляет собой описание алгоритма и данных на

некотором языке программирования, предназначенное для последующего

автоматического выполнения.

Способы описания алгоритмов

К основным способам описания алгоритмов можно отнести следующие:

словесно-формульный;

структурный или блок-схемный;

с помощью граф-схем;

с помощью сетей Петри.

Перед составлением программ чаще всего используются словесно-формульный

и блок-схемный способы. Иногда перед составлением программ на

низкоуровневых языках программирования типа языка Ассемблера алгоритм

программы записывают, пользуясь конструкциями некоторого высокоуровнего

языка программирования. Удобно использовать программное описание

алгоритмов функционирования сложных программных систем. Так, для

описания принципов функционирования ОС использовался Алголоподобный

высокоуровневый язык программирования.

При словесно-формульном способе алгоритм записывается в виде текста с

формулами по пунктам, определяющим последовательность действий.

Пусть, например, необходимо найти значение следующего выражения:

у = 2а – (х+6).

Словесно-формульным способом алгоритм решения этой задачи может быть

записан в следующем виде:

1. Ввести значения а и х.

2. Сложить х и 6.

3. Умножить a на 2.

4. Вычесть из 2а сумму (х+6).

5. Вывести у как результат вычисления выражения.

При блок-схемном описании алгоритм изображается геометрическими

фигурами (блоками), связанными по управлению линиями (направлениями

потока) со стрелками. В блоках записывается последовательность действий.

Данный способ по сравнению с другими способами записи алгоритма имеет ряд

преимуществ. Он наиболее нагляден: каждая операция вычислительного

процесса изображается отдельной геометрической фигурой. Кроме того,

Page 3: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

графическое изображение алгоритма наглядно показывает разветвления путей

решения задачи в зависимости от различных условий, повторение отдельных

этапов вычислительного процесса и Другие детали.

Оформление программ должно соответствовать определенным требованиям. В

настоящее время действует единая система программной документации

(ЕСПД), которая устанавливает правила разработки, оформления программ и

программной документации. В ЕСПД определены и правила оформления блок-

схем алгоритмов (ГОСТ 10.002-80 ЕСПД, ГОСТ 10.003-80 ЕСПД).

Операции обработки данных и носители информации изображаются на схеме

соответствующими блоками. Большая часть блоков по построению условно

вписана в прямоугольник со сторонами а и b. Минимальное значение а = 10

мм, увеличение а производится на число, кратное 5 мм. Размер b=1,5a. Для от

дельных блоков допускается соотношение между а и b, равное 1:2. В пределах

одной схемы рекомендуется изображать блоки одинаковых размеров. Все блоки

нумеруются. Виды и назначение основных блоков приведены в табл. 1.

Таблица 1. Условные обозначения блоков схем алгоритмов

Наименование Обозначение Функции

Процесс

Выполнение операции или группы

операций, в результате которых изменяется

значение, форма представления или

расположение данных.

Ввод-вывод

Преобразование данных в форму,

пригодную для обработки (ввод) или

отображения результатов обработки

(вывод).

Решение

Выбор направления выполнения алгоритма

в зависимости от некоторых переменных

условий.

Предопределенный

процесс

Использование ранее созданных и отдельно

написанных программ (подпрограмм).

Документ

Вывод данных на бумажный носитель.

Магнитный диск Ввод-вывод данных, носителем которых

служит магнитный диск.

Пуск-останов Начало, конец, прерывание процесса

обработки данных.

Соединитель Указание связи между прерванными

линиями, соединяющими блоки.

Межстраничный

соединитель

Указание связи между прерванными

линиями, соединяющими блоки,

Page 4: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

расположенные на разных листах.

Комментарий

Связь между элементом схемы и

пояснением.

Линии, соединяющие блоки и указывающие последовательность связей между

ними, должны проводится параллельно линиям рамки. Стрелка в конце линии

может не ставиться, если линия направлена слева направо или сверху вниз. В

блок может входить несколько линий, то есть блок может являться преемником

любого числа блоков. Из блока (кроме логического) может выходить только

одна линия. Логический блок может иметь в качестве продолжения один из

двух блоков, и из него выходят две линии. Если на схеме имеет место слияние

линий, то место пересечения выделяется точкой. В случае, когда одна линия

подходит к другой и слияние их явно выражено, точку можно не ставить.

Схему алгоритма следует выполнять как единое целое, однако в случае

необходимости допускается обрывать линии, соединяющие блоки.

Блок-схема должна содержать все разветвления, циклы и обращения к

подпрограммам, содержащиеся в программе.

Структурные схемы алгоритмов

Одним из свойств алгоритма является дискретность — возможность

расчленения процесса вычислений, предписанных алгоритмом, на отдельные

этапы, возможность выделения участков программы с определенной

структурой. Можно выделить и наглядно представить графически три

простейшие структуры:

последовательность двух или более операций;

выбор направления;

повторение.

Любой вычислительный процесс может быть представлен как комбинация этих

элементарных алгоритмических структур. Соответственно, вычислительные

процессы, выполняемые на ЭВМ по заданной программе, можно разделить на

три основных вида:

линейные;

ветвящиеся;

циклические.

Линейным принято называть вычислительный процесс, в котором операции

выполняются последовательно, в порядке их записи. Каждая операция является

самостоятельной, независимой от каких-либо условий. На схеме блоки,

отображающие эти операции, располагаются в линейной последовательности.

Линейные вычислительные процессы имеют место, например, при вычислении

арифметических выражений, когда имеются конкретные числовые данные и

над ними выполняются соответствующие условию задачи действия. На рис.

Page 5: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

11.1, а показан пример линейного алгоритма, определяющего процесс

вычисления арифметического выражения

у=(b2-ас):(а+с).

Вычислительный процесс называется ветвящимся, если для его реализации

предусмотрено несколько направлений (ветвей). Каждое отдельное

направление процесса обработки данных является отдельной ветвью

вычислений. Ветвление в программе — это выбор одной из нескольких

последовательностей команд при выполнении программы. Выбор направления

зависит от заранее определенного признака, который может относиться к

исходным данным, к промежуточным или конечным результатам. Признак

характеризует свойство данных и имеет два или более значений.

Ветвящийся процесс, включающий в себя две ветви, называется простым, более

двух ветвей — сложным. Сложный ветвящийся процесс можно представить с

помощью простых ветвящихся процессов.

Направление ветвления выбирается логической проверкой, в результате

которой возможны два ответа: «да» — условие выполнено и «нет» — условие

не выполнено.

Следует иметь в виду, что, хотя на схеме алгоритма должны быть показаны все

возможные направления вычислений в зависимости от выполнения

определенного условия (или условий), при однократном прохождении

программы процесс реализуется только по одной ветви, а остальные

исключаются. Любая ветвь, по которой осуществляются вычисления, должна

приводить к завершению вычислительного процесса.

На рис. 11.1,б показан пример алгоритма с разветвлением для вычисления

следующего выражения:

Y = (а+b), если Х <0;

с/b, если Х>0.

Page 6: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

а б

Рис. 11.1. Примеры алгоритмов: а) линейный алгоритм; б) ветвящийся

алгоритм

Циклическими называются программы, содержащие циклы. Цикл — это

многократно повторяемый участок программы.

В организации цикла можно выделить следующие этапы:

• подготовка (инициализация) цикла (И);

• выполнение вычислений цикла (тело цикла) (Т);

• модификация параметров (М);

• проверка условия окончания цикла (У).

Порядок выполнения этих этапов, например, Т и М, может изменяться. В

зависимости от расположения проверки условия окончания цикла различают

циклы с нижним и верхним окончаниями (рис. 11.2). Для цикла с нижним

окончанием (рис. 11.2, а) тело цикла выполняется как минимум один раз, так

как сначала производятся вычисления, а затем проверяется условие выхода из

Page 7: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

цикла. В случае цикла с верхним окончанием (рис. 11.2, б) тело цикла может не

выполниться ни разу в случае, если сразу соблюдается условие выхода.

а б

Рис. 11.2. Примеры циклических алгоритмов

Цикл называется детерминированным, если число повторений тела цикла

заранее известно или определено. Цикл называется итерационным, если число

повторений тела цикла заранее неизвестно, а зависит от значений параметров

(некоторых переменных), участвующих в вычислениях.

Пример циклического алгоритма вычисления суммы десяти чисел.

2. Сложность алгоритма

Понятие сложности алгоритма

Сложность- количественная оценка ресурсов, затрачиваемых алгоритмом.

Ресурсы:

1. Человеческий (разработка и понимание алгоритма)

2. Вычислительный (выполнение).

1. интеллектуальная сложность. При анализе интеллектуальной сложности

алгоритма исследуется понятность алгоритмов и сложность их

разработки.

2. временной сложность, пространственная сложность. Пространственная

сложность характеризует объем памяти, необходимый для выполнения

программы

Все три формы сложности обычно взаимосвязаны. Как правило, при разработке

алгоритма с хорошей временной оценкой сложности приходится жертвовать

его пространственной и/или интеллектуальной сложностью. Например,

алгоритм быстрой сортировки существенно быстрее, чем алгоритм сортировки

Page 8: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

выборками. Плата за увеличение скорости сортировки выражена в большем

объеме необходимой для сортировки памяти. Необходимость дополнительной

памяти для быстрой сортировки связана с многократными рекурсивными

вызовами.

Алгоритм быстрой сортировки характеризуется также и большей

интеллектуальной сложностью по сравнению с алгоритмом сортировки

вставками.

Page 9: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

2. Сложность алгоритма Понятие сложности алгоритма

Сложность- количественная оценка ресурсов, затрачиваемых алгоритмом.

Ресурсы:

3. Человеческий (разработка и понимание алгоритма)

4. Вычислительный (выполнение).

3. интеллектуальная сложность. При анализе интеллектуальной сложности

алгоритма исследуется понятность алгоритмов и сложность их

разработки.

4. временной сложность, пространственная сложность. Пространственная

сложность характеризует объем памяти, необходимый для выполнения

программы

Все три формы сложности обычно взаимосвязаны. Как правило, при разработке

алгоритма с хорошей временной оценкой сложности приходится жертвовать

его пространственной и/или интеллектуальной сложностью. Например,

алгоритм быстрой сортировки существенно быстрее, чем алгоритм сортировки

выборками. Плата за увеличение скорости сортировки выражена в большем

объеме необходимой для сортировки памяти. Необходимость дополнительной

памяти для быстрой сортировки связана с многократными рекурсивными

вызовами.

Алгоритм быстрой сортировки характеризуется также и большей

интеллектуальной сложностью по сравнению с алгоритмом сортировки

вставками.

Оценка элементарных алгоритмов

После введения элементарных операций анализ трудоемкости основных

алгоритмических конструкций в общем виде сводится к следующим

положениям:

А) Конструкция «Следование»

Трудоемкость конструкции есть сумма трудоемкостей

блоков, следующих друг за другом.

F «следование» = f1 + … + fk, где k – количество блоков.

B) Конструкция «Ветвление»

if ( l ) then

fthen с вероятностью p

else

felse с вероятностью (1-p)

Page 10: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Общая трудоемкость конструкции «Ветвление» требует анализа

вероятности выполнения переходов на блоки «Then» и «Else» и определяется

как:

F «ветвление» = fthen * p + felse * (1-p).

C) Конструкция «Цикл»

for i 1 to N

end

После сведения конструкции к элементарным операциям ее трудоемкость

определяется как:

F «цикл» = 1+3*N+N*f«тела цикла»

Примеры анализа простых алгоритмов

Пример 1 Задача суммирования элементов квадратной матрицы

SumM (A, n; Sum)

Sum 0

For i 1 to n

For j 1 to n

Sum Sum + A[i,j]

end for

Return (Sum)

End

Алгоритм выполняет одинаковое количество операций при

фиксированном значении n, и следовательно является количественно-

зависимым. Применение методики анализа конструкции «Цикл » дает:

FA(n)=1+1+ n *(3+1+ n *(3+4))=7 n 2+4* n +2 = (n

2), заметим, что под n

понимается линейная размерность матрицы, в то время как на вход алгоритма

подается n 2 значений.

Пример 2 Задача поиска максимума в массиве

MaxS (S,n; Max)

Max S[1]

For i 2 to n

if Max < S[i]

then Max S[i]

end for

return Max

End

i 1

i i+1

if i N

Page 11: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Данный алгоритм является количественно-параметрическим, поэтому для

фиксированной размерности исходных данных необходимо проводить анализ

для худшего, лучшего и среднего случая.

А). Худший случай

Максимальное количество переприсваиваний максимума (на каждом

проходе цикла) будет в том случае, если элементы массива отсортированы по

возрастанию. Трудоемкость алгоритма в этом случае равна:

FA^(n)=1+1+1+ (n-1) (3+2+2)=7 n - 4 = (n).

Б) Лучший случай

Минимальное количество переприсваивания максимума (ни одного на

каждом проходе цикла) будет в том случае, если максимальный элемент

расположен на первом месте в массиве. Трудоемкость алгоритма в этом случае

равна:

FA(n)=1+1+1+ (n-1) (3+2)=5 n - 2 = (n).

В) Средний случай

Алгоритм поиска максимума последовательно перебирает элементы

массива, сравнивая текущий элемент массива с текущим значением максимума.

На очередном шаге, когда просматривается к-ый элемент массива,

переприсваивание максимума произойдет, если в подмассиве из первых к

элементов максимальным элементом является последний. Очевидно, что в

случае равномерного распределения исходных данных, вероятность того, что

максимальный из к элементов расположен в определенной (последней) позиции

равна 1/к. Тогда в массиве из n элементов общее количество операций

переприсваивания максимума определяется как:

0,57γNLnHn iN

i

,)(/11

Величина Hn называется n-ым гармоническим числом. Таким образом,

точное значение (математическое ожидание) среднего количества операций

присваивания в алгоритме поиска максимума в массиве из n элементов

определяется величиной Hn (на бесконечности количества испытаний), тогда:

FA(n)=1 + (n-1) (3+2) + 2 (Ln(n) + )=5 n +2 Ln(n) - 4 +2 = (n).

Page 12: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

3. Оценки сложности

Асимптотический анализ функций

При анализе поведения функции трудоемкости алгоритма часто

используют принятые в математике асимптотические обозначения,

позволяющие показать скорость роста функции, маскируя при этом конкретные

коэффициенты.

Такая оценка функции трудоемкости алгоритма называется сложностью

алгоритма и позволяет определить предпочтения в использовании того или

иного алгоритма для больших значений размерности исходных данных.

В асимптотическом анализе приняты следующие обозначения [6]:

1. Оценка (тетта)

Пусть f(n) и g(n) – положительные функции положительного аргумента, n

≥ 1 (количество объектов на входе и количество операций – положительные

числа), тогда:

f(n) = (g(n)), если существуют

положительные с1, с2, n0, такие, что:

с1 * g(n) f(n) c2 * g(n), при n > n0

Обычно говорят, что при этом

функция g(n) является асимптотически точной оценкой функции f(n), т.к. по

определению функция f(n) не отличается от функции g(n) с точностью до

постоянного множителя.

Отметим, что из f(n) = (g(n)) следует, что g(n) = (f(n)).

Примеры:

1) f(n)=4n2+nlnN+174 – f(n)= (n

2);

2) f(n)=(1) – запись означает, что f(n) или равна константе, не равной

нулю, или f(n) ограничена константой на : f(n) = 7+1/n = (1).

2. Оценка О (О большое)

В отличие от оценки , оценка О требует только, чтобы функция f(n) не

превышала g(n) начиная с n > n0, с точностью до постоянного множителя:

c > 0, n0 > 0 :

0 f(n) c * g(n), n n0

cg(n)

f(n)

n0

f,g

n

c2g(n)

f(n)

c1g(n)

Page 13: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Вообще, запись O(g(n)) обозначает класс функций, таких, что все они

растут не быстрее, чем функция g(n) с точностью до постоянного множителя,

поэтому иногда говорят, что g(n) мажорирует функцию f(n).

Например, для всех функций:

f(n)=1/n,

f(n)= 12,

f(n)=3*n+17,

f(n)=n*Ln(n),

f(n)=6*n2 +24*n+77

будет справедлива оценка О(n2 )

Указывая оценку О есть смысл указывать наиболее «близкую»

мажорирующую функцию, поскольку например для f(n)= n2 справедлива

оценка О(2n), однако она не имеет практического смысла.

3. Оценка (Омега)

В отличие от оценки О, оценка является оценкой снизу – т.е.

определяет класс функций, которые растут не медленнее, чем g(n) с точностью

до постоянного множителя:

c > 0, n0 >0 :

0 c * g(n) f(n)

Например, запись (n*Ln(n)) обозначает класс функций, которые растут

не медленнее, чем g(n) = n*Ln(n), в этот класс попадают все полиномы со

степенью большей единицы, равно как и все степенные функции с основанием

большим единицы.

Асимптотическое обозначение О восходит к учебнику Бахмана по теории

простых чисел (Bachman, 1892), обозначения , введены Д. Кнутом- (Donald

Knuth) [6].

Отметим, что не всегда для пары функций справедливо одно из

асимптотических соотношений, например для f(n)=n1+sin(n)

и g(n)=n не

выполняется ни одно из асимптотических соотношений.

В асимптотическом анализе алгоритмов разработаны специальные

методы получения асимптотических оценок, особенно для класса рекурсивных

алгоритмов. Очевидно, что оценка является более прдпочтительной, чем

оценка О. Знание асимптотики поведения функции трудоемкости алгоритма -

его сложности, дает возможность делать прогнозы по выбору более

F(n)

cg(n)

Page 14: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

рационального с точки зрения трудоемкости алгоритма для больших

размерностей исходных данных.

Правила вычислений

Пусть T1(n) и T2(n) – время выполнения двух программных фрагментов P1

и P2. T1(n) имеет степень роста О(f(n)) , а T2(n) – О(g(n)).

1. Правило сумм

T1(n) + T2(n), то есть время последовательного выполнения

фрагментов P1 и P2, имеет степень роста О(max (f(n),g(n)))

Если f(n) ≤ g(n), то О(f(n) + g(n))≡ О(f(n))

Если с – положительная константа, то О(f(n)+с) ≡ О(f(n))

2. Правило произведений

T1(n)∙T2(n), то есть время вложенного выполнения фрагментов P1 и

P2, имеет степень роста О((f(n)∙g(n))

Если с – положительная константа, то О(с∙f(n)) ≡ О(f(n))

Общие правила вычисления О оценки:

1. Время выполнения присваивания, чтения и записи имеет порядок

О(1).

2. Время выполнения последовательности операторов по правилу

сумм оценивается наибольшим временем выполнения оператора в

данной последовательности.

3. Время выполнения условий состоит из времени вычисления

логического выражения (имеет порядок роста О(1)) и времени

выполнения условно исполняемых операторов => имеет порядок

роста О(max (операторы then, операторы else))

4. Время выполнения цикла состоит из времени инициализации,

вычисления условия прекращения, модификации (имеют порядок

роста О(1)) и времени выполнения операторов тела цикла => имеет

порядок роста <кол-во итераций>*О(max (операторы тела цикла))

Page 15: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

4. Оценка сложности рекурсивных алгоритмов

Существуют три различных подхода к решению рекуррентных соотношений.

1. В рекуррентном соотношении в правую часть последовательно

подставляются выражения для T(m), m < п, так, чтобы исключить из правой

части все выражения Т(m) для m > 1, оставляя только Т(1). Поскольку Т(1)

всегда является константой, то в результате получим формулу для Т(п),

содержащую только п и константы. Такая формула и называется "замкнутой

формой" для Т(п).

2. Нахождение функции f(n), которая мажорировала бы Т(п) для всех значений п

(т.е. для всех п > 1 должно выполняться неравенство Т(п) < f(n)). Иногда

сначала мы будем определять только вид функции f(n), предполагая, что она

зависит от некоторых пока неопределенных параметров (например, f(n) = an2,

где a - неопределенный параметр), затем подбираются такие значения

параметров, чтобы для всех значений n выполнялось неравенство Т(п) ≤ f(n).

3. Третий подход заключается в использовании общих решений определенных

рекуррентных соотношений.

Рассмотрим на примере сортировки слиянием, для которой можно записать

следующее рекуррентное соотношение:

В (1) константа с1 соответствует

фиксированному количеству шагов, выполняемых над списком L длины 1. Если

п>1, время выполнения процедуры обработки двух списков можно разделить на

две части:

1. проверка того, что п ≠ 1, разбиение на две равные части и вызов процедуры

слияния. Проверка и разбиение требуют фиксированного времени, слияние –

пропорционального п. Поэтому можно выбрать константу с2, такую, что

время выполнения этой части будет ограничено с2п.

2. два рекурсивных вызова для списков длины п /2, которые требуют времени

2T(п /2).

Отметим, что (1) верно, когда п – четно, => формулу для Т(п) в замкнутой

форме (т.е. когда она не включает выражений Т(m) m < п ) можно получить

только в случае, если п является степенью 2. Но для нечетных п легко показать,

что Т(2i)≤Т(п)≤ Т(2

i+1), если 2

i≤ п ≤ 2

i+1.

1. Оценка решения рекуррентных соотношений методом подстановки

Позволяет получить точное решение для Т(п), не требует предположений об

оценочной функции, но на практике часто приводит к решению в виде

)1(1,

22

1,

)(2

1

nnc

nT

nc

nT

Page 16: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

достаточно сложных сумм, от которых не всегда можно освободиться.

Рассмотрим этот подход. Заменим в (1) п на п/2 , получим

Т(п/2) ≤ 2Т(п/4) + с2п/2 .

Подставляем правую часть в (1), будем иметь

Т(п) ≤ 2(2Т(п/4) + с2п/2) + с2п/2 = 4Т(п/4) + 2с2п (2).

Аналогично заменяя в (1) п на п/4 , получаем оценку

Т(п/4) ≤ 2Т(п/8) + с2п/4 .

Подставляем ее в (2) , получим

Т(п) ≤ 8Т(п/8) + 3с2п .

Индукцией по i для любого i :

Т(п) ≤ 2i Т(п/2

i) + iс2п (3) .

Предположим, что п является степенью 2, например, п = 2k

, тогда при i=k в

правой части (3) будет стоять Т(1):

Т(п) ≤ 2k Т(1) + kс2п (4) .

Поскольку п = 2k , то k = log n . Так как Т(1)≤ с1, то (4) =>

Т(п) ≤ с1п + с2п log n .

Т.о. получили верхнюю границу для Т(п) - имеет порядок роста не более О(п

log n).

2. Оценка решений рекуррентных соотношений

Пример 1. Предположим, что Т(п) = an log n, где а — пока не определенный

параметр. Подставляя n = 1, видим, что эта оценка "не работает", так как при п

= 1 выражение an logn равно 0, независимо от значения а. Попробуем

применить другую функцию: Т(п) = an logn + b. При п = 1 эта оценка

"работает", если положить b >= с1. В соответствии с методом математической

индукции предполагаем, что для всех k< п выполняется неравенство

T(k) < ak log п + b, (9.2)

и попытаемся доказать, что Т(п) < an logn + b.

Пусть п ≥ 2. Из неравенств (9.1) имеем Т(п) < 2Т(п/2) + с2п. Полагая k = п /2,

используем в последнем неравенстве оценку (9.2). Получаем:

T(n)<2(a п/2 log п/2 + b) + c2n =)

= an log n - an + с2п + 2b < an log n + b.

Последнее неравенство получено в предположении, что а > с2 + b.

Таким образом, видим, что будет справедлива оценка Т(п) <= an logn + b,

если будут выполняться неравенства b >= с1 и а >= b + с2 . В данном случае

можно удовлетворить этим неравенствам, если положить b = с1 и а = с1 + с2.

Отсюда мы заключаем, То для всех п > 1 выполняется неравенство

Т(п) < (с1 + с2 )п log n + с1 . (9.4)

Другими словами, Т(п) имеет порядок О(п log n).

Исходя из рассмотренного примера, сделаем два замечания:

Page 17: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1. Если мы предполагаем, что Т(п) имеет порядок О(f(n)), но по индукции мы

не можем доказать неравенства Т(п) < сf(n), то это еще не значит, что Т(п) ≠

O(f(n)). Возможно, надо просто добавить константу к функции cf(n), например

можно попытаться доказать неравенство Т(п) < cf(n) - 1!

2. Мы не определили точной асимптотической степени роста оценочной

функции f(n), мы только показали, что она растет не быстрее, чем О(п log n).

Если мы возьмем в качестве оценки более медленно растущие функции,

например, такие как f(n) = an или f(n) = an log log n, то не сможем доказать, что

Т(п) ≤ f(n). Но в чем причина этого: неверный метод доказательства, или для

данного алгоритма в принципе невозможна оценочная функция с меньшей

степенью роста? Чтобы ответить на этот вопрос, надо подробнее

проанализировать исследуемый алгоритм и рассмотреть время выполнения в

самом худшем случае. Для нашей процедуры mergesort надо показать, что

действительно время выполнения равно Ω(п log n). Фактически мы показали,

что время выполнения процедуры не превосходит сn logn для любых входных

но не для "самых плохих" входных данных. Случай возможных "самых плохих"

входных данных мы оставляем в качестве упражнения.

3. Общее решение большого класса рекуррентных уравнений

Если, как мы предположили, п = bk, тогда при i = k Т(п/ b

k) = Т(1) = 1 и мы

получаем формулу

Т(n)= ak + ∑ a

j d ( b

k - j). (9.16)

Так как k = log b n, то первое выражение в (9.16) можно записать как a log

b n

или, что эквивалентно, как n log

ba. Таким образом, это выражение обозначает п в

степени, которая зависит от а и b. Например, в случае процедуры mergesort a =

b=2, поэтому первое выражение равно просто п. В общем случае, чем больше а

(т.е. надо решить большее количество подзадач), тем больший показатель

степени п. При больших значениях b (чем больше b, тем меньше размер

подзадач) показатель степени п будет меньше.

Однородные и частные решения

Интересно исследовать, какова роль обоих выражений в формуле (9.16).

Первое выражение ak или n

logba называется однородным решением (по аналогии

с дифференциальными уравнениями). Однородное решение — это точное

решение уравнения (9.14), когда функция d(n), называемая управляющей

функцией, равна 0 для всех n. Другими словами, однородное решение

соответствует стоимости выполнения все подзадач, если их можно объединить

"бесплатно".

С другой стороны, второе выражение формулы (9.16) соответствует

стоимости создания подзадач и комбинирования их результатов. Назовем это

выражение частным решением (также по аналогии с теорией

Page 18: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

дифференциальных уравнений). Частное решение зависит как от управляющей

функции, так и от количества и размера подзадач.

Существует практическое правило:

Если однородное решение больше управляющей функции, то

частное решение имеет тот же порядок роста, что и однородное решение.

Если же управляющая функция растет на порядок nе (для

некоторого е > 0) быстрее однородного решения, тогда частное решение

имеет такой же порядок роста, как и управляющая функция.

Когда управляющая функция имеет с однородным решением

одинаковый порядок роста или растет не медленнее, чем logk

n для

некоторого k, тогда частное решение растет как управляющая функция,

умноженная на log n.

При исследовании реализации любого алгоритма важно распознать, когда

однородное решение будет больше управляющей функции, так как в этом

случае любой более быстрый способ объединения подзадач не окажет

существенного влияния на эффективность всего алгоритма. В этой ситуации

для ускорения выполнения алгоритма надо и уменьшить количество подзадач,

или уменьшить их размер. Только это может привести к тому, что однородное

решение будет меньше общего времени выполнения алгоритма.

Если упр. функция превышает однородное решение, тогда надо попытаться

уменьшить эту функцию. Например, в случае процедуры mergesort, где a = b =

2 и d(n) = сп, мы видели, что частное решение имеет порядок О(п log n). Если

сделать функцию d(n) растущей медленнее, чем линейная, например как п0.9

,

тогда, как мы увидим далее, частное решение будет расти медленнее, чем

линейная функция, и общее время выполнения алгоритма будет иметь порядок

О(п), такой же, как и однородное решение.1

Мультипликативные функции

Частное решение в формуле (9.16) оценить достаточно трудно, даже если

известен вид функции d(n). Но для определенного, достаточно широкого класса

функций d(n) можно найти точное решение (9.16). Будем говорить, что функция

f целочисленного аргумента называется мультипликативной, если для всех

положительных целых чисел х и у справедливо равенство f(xy) = f(x)f(y).

Пример 9.2. Для нас наибольший интерес представляют мультипликативные

функции вида па, где α — некоторая положительная константа. Чтобы показать,

что функция f(n) = па является мультипликативной, достаточно заметить, что

(ху)а = х

ау

а.

Пусть в (9.16) функция d(n) является мультипликативной, тогда d(bk - 1

) =

(d(b))k - 1

. В этом случае частное решение запишется в следующем виде:

Page 19: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1)(

)(

1)(

1)(

)()(

)())((

1

1

0

1

0

bd

a

bda

bd

a

bd

a

bdbd

abdbda

kk

k

k

jk

j

k

j

kjkj

Теперь необходимо рассмотреть три ситуации, зависящие от того, будет ли

параметр а больше, меньше или равен d(b).

1. Если а > d(b), тогда последнее выражение в (9.17) имеет порядок О(ак),

который можно переписать как n log

ba, поскольку k = logb n. В этом случае

частное и однородные решения имеют одинаковый порядок роста, который

зависит только от а и b, но не от управляющей функции. Поэтому в данной

ситуации уменьшение времени выполнения алгоритма можно достичь путем

уменьшения а или увеличения b, уменьшение порядка роста функции d(n) здесь

не поможет.

2. Если а < d(b), тогда последнее выражение в (9.17) имеет порядок

O(d(b)h), или, что то же самое, O(n

log b d(b)). В этом случае частное решение

превышает однородное. Поэтому для уменьшения времени выполнения

алгоритма можно манипулировать как функцией dn), так и параметрами а и b.

В важном частном случае, когда d(n) = na, d(b) будет равно b

а и logb(b

a) = а.

Тогда частное решение имеет порядок О(па) или O(d(n)).

3. Если a = d(b), тогда надо пересмотреть решение (9.17), поскольку в

данном случае нельзя применять формулу суммирования членов

геометрической прогрессии. В этой ситуации суммируем следующим образом:

nnkbdbdbd

abdbda b

bdkk

j

k

jk

j

k

j

kjkj b log)(1)()(

)())(()(log

1

0

1

0

1

0

Поскольку a = d(b), то частное решение (9.18) равно однородному решению,

умноженному на logb n. Здесь опять частное решение превосходит однородное.

В частном случае, когда d(n) = па, решение (9.18) имеет порядок O(n

a logn).

Пример 9.3. Рассмотрим следующие рекуррентные уравнения с начальным

значением Т(1) = 1.

1. Т(п) = 4Т(п/2) + п.

2. Т(п) = 4Т(п/2) + п 2.

3. Т(п) = 4Т(п/2) + п 3.

В каждом уравнении а = 4 и b = 2, следовательно, однородное решение равно

п 2

. В уравнении (1) d(n) = п, поэтому d(b) = 2. Поскольку а = 4 > d(b), то

частное решение также имеет порядок п2. Поэтому здесь Т(п) = О(п

2).

В уравнении (3) d(n) = пг, d(b) = 8 и а < d(b). Тогда частное решение имеет

порядок O(nlog b d(b)

) = О(п3) и Т(п) в этом уравнении также равно О(п

3).

Page 20: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

В уравнении (2) d(b) = 4 = а, поэтому решение дается формулой (9.18). Здесь

как частное решение, так и Т(п) имеют порядок О(п2 log n).

Другие управляющие функции

Существуют другие типы управляющих функций, отличные от

мультипликативных, которые позволяют получить замкнутую форму решения

(9.16). Мы рассмотрим только два примера таких функций. В первом примере

получаем небольшое обобщение мультипликативных функций, а именно, здесь

рассматриваются мультипликативные функции, умноженные на константу,

которая больше или равна единице. Во втором примере просто показан частный

случай функции d(п), позволяющий получить замкнутую форму решения (9.16).

Пример 9.4. Рассмотрим следующее рекуррентное уравнение:

Т(1) = 1,

T(n) = ЗТ(п/2) + 2п1.5

.

Выражение 2п1.5

не является мультипликативной функцией, но функция nl..5

является. Сделаем замену U(п) = Т(п)/2 для всех п. Тогда исходное

рекуррентное перепишется в виде

U(1) = 1/2,

U(п) = З U(п/2) + п1.5

.

Если бы U(1) равнялось 1, тогда однородное решение равнялось бы nlog3

<

nl..59

. Для U(1) = 1/2 можно показать, что однородное решение не больше n 1..59

/2, т.е. имеет порядок О(nl..59

). На частное решение значение U(1) не влияет.

Поскольку в данном случае а = 3, b = 2 и б1..5

= 2.83 < а, то частное решение, а

также и U(n) имеют порядок роста О(n1.59

). Так как Т(п) = 2U(n), то Т(п) тоже

имеет порядок O(n1.59

), точнее О(nlog 3

)D

Пример 9.5. Рассмотрим рекуррентное уравнение

Т(1) = 1,

Т(п) = 2Т(п/2) + п logn.

Легко проверить, что в данном случае однородное решение равно п,

поскольку а = b = 2. Но функция d(n) = п log n мультипликативной не является,

поэтому надо попытаться найти значение суммы в формуле (9.16). В данном

случае имеем

1

0

1

0

1 )1(2)(2)2log(22k

j

k

j

kkjkjkj kkjk

Так как k = log n, то частное решение имеет порядок О(п log2n). Поскольку

здесь частное решение больше однородного, то отсюда следует, что Т(п) также

будет иметь порядок О(п log2n).

Page 21: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

5. Методы разработки алгоритмов

К настоящему моменту разработан ряд эффективных методов, позволяющих

получать эффективные алгоритмы решения больших классов задач.

Рассмотрим наиболее распространенные методы. В качестве примера для

иллюстрации будем использовать алгоритмы на графах.

Полный перебор

«пузырьковая сортировка»

Поиск в неупорядоченном массиве

Нахождение кратчайших путей:

В заданном взвешенном связном графе найти расстояние (длину кратчайшего

пути) от выделенной вершины s до вершины t. Веса всех ребер строго

положительны.

Рекурсивный алгоритм: Совершить обход графа в глубину, при каждом "шаге

вперед" прибавляя длину ребра к длине текущего пути, при каждом возврате -

отнимая длину этого ребра от длины текущего пути. При движении "вперед"

пометки посещенности вершин ставятся, при "откате" - снимаются. По

достижении выделенной вершины t производится сравнение длины текущего

пути с ранее найденным минимумом.

Реализация

Пусть граф задан матрицей смежности sm, а массив mark хранит информацию о

посещениях вершин. Уменьшение длины пути "на возврате" совершается

рекурсией автоматически, поскольку в ее заголовке использован параметр-

значение, а вот аналогичное обнуление соответствующих позиций массива

mark приходится делать вручную, поскольку задавать массив параметром-

значением чересчур накладно:

procedure rasst(v: byte; r: longint);

var i: byte;

begin

if v = t

then if r< min then min:= r

else

else for i:= 1 to N do

if (mark[i]=0)and(sm[v,i]<>0)

then begin

mark[i]:=1;

rasst(i,r+sm[v,i]);

mark[i]:=0

Page 22: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

end

end;

begin

...

for i:= 1 to N do mark[i]:= 0;

min:= MaxLongInt;

mark[s]:= 1;

rasst(s,0);

mark[s]:= 0;

...

end.

Сложность рекурсивного алгоритма пропорциональна N!

Page 23: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

«Разделяй и властвуй» (декомпозиция)

Разбиение задачи размера n на более мелкие подзадачи таким образом, что на

основе их решений можно легко получить решение исходной задачи.

Сортировка слиянием.

Легкость понимания и разработки => популярность метода

Баланс подзадач. Разбиение на задачи равного размера обеспечивает

наибольшую эффективность.

«Жадные» алгоритмы

Пример: монетки 25, 10, 5 и 1, нужно получить 63 коп.

На каждой стадии алгоритм выбирает тот вариант, который является «локально

оптимальным» в том или ином смысле. Пример: Сортировка простым выбором.

Но: 11, 5 и 1, получить 15 коп. – «жадный» алгоритм не оптимален.

Пример: алгоритм Дейкстры – задача нахождения кратчайших путей от

избранной вершины (источника) ко всем другим вершинам.

Алгоритм строит множество S вершин, для которых кратчайшие пути от

источника уже известны. На каждом шаге к S добавляется та из оставшихся

вершин, расстояние до которой от источника меньше, чем для других

оставшихся. На каждом шаге алгоритма используется массив D длин

кратчайших путей. Когда S будет содержать все вершины графа, D будет

содержать все кратчайшие пути.

V=1,2,…,n, 1 – источник, С – матрица стоимостей (10000 – для отсутствия

пути).

Procedure Dijkstra;

Begin

S:=1;

For i:=1 to n do

D[i]:=C[1,i];

For i:=1 to n-1 do

Begin

Выбор из множества V\S вершины w| D[w] минимально;

Добавить w к S;

For каждая вершина v из V\S do

D[v]:=min(D[v]+C[w,v]);

End;

End.

Алгоритм Дейкстры

Page 24: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1. Расстояние от s до s, конечно же, равно 0. Кроме того, это расстояние уже

никогда не сможет стать меньше - ведь веса всех ребер графа у нас

положительны. Таким образом:

dist[s]:= 0; done[s]:= true; last:= s;

2. Повторить N-1 раз следующие действия:

1. для всех непомеченных вершин х, связанных ребром с вершиной

last, необходимо пересчитать расстояние:

dist[x]:= min(dist[x], dist[last]+

sm[last,x]);

2. среди всех непомеченных вершин найти минимум в массиве dist:

это будет новая вершина last;

3. пометить эту новую вершину в массиве done.

Реализация

Функция поиска меньшего из двух целых чисел min, использованная в тексте

программы, тривиальна.

dist[s]:= 0;

done[s]:= true;

last:= s;

for i:= 1 to N-1 do

begin

for x:= 1 to N do

if (sm[last,x]<>0)and(not done[x])

then dist[x]:= min(dist[x],dist[last]+

sm[last,x]);

min_dist:= MaxLongInt;

for x:= 1 to N do

if (not done[x])and(min_dist>dist[x])

then begin

min_dist:= dist[x];

last:= x;

end;

done[last]:= true;

end.

Сложность O(n2)

«Жадный» алгоритм дает не оптимальное, но достаточно хорошее решение (на

несколько процентов худшее) за время, гораздо меньшее простого перебора.

Пример: задача коммивояжера.

Выбор ребра (в сочетании с уже выбранными):

Не приводит к появлению вершины со степенью 3 и более

Не образует цикл (кроме последнего ребра)

Page 25: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

С (1, 7)

B (4, 3)

A (0, 0)

D (15, 7)

E (15, 4)

F (18, 0)

DE – 3

BC, AB, EF – 5

AC – 7,08 – Нет! (цикл с AB,BC)

DF – то же

BE, BD – степень превышает

CD

AF

Вес - 50 (на 4% меньше оптимального)

Алгоритм Флойда.

Рассматривается задача нахождения кратчайших путей между

всеми парами узлов сети

G=(V,E), где V=vi i=1,n - множество вершин графа, E -

множество дуг соединяющих вершины графа E = (vi,vj) i не

равно j. Граф G - ориентированный граф, задается матрицей

смежностей, например.

Фигура 1: Простой ориентированный граф G, и его матрица

смежностей, A.

Page 26: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Элементы матрицы смежности определяются следующим

образом:

aij = 1, если существует дуга из i в j, aij = 0 , если нет дуги из i

в j.

Каждой дуге ставится в соответствие число cij - длина дуги

направленной из вершины i в вершину j.

Обозначим d*ij - кратчайший путь из вершины i в j. Пусть dij

- наилучшая оценка длины кратчайшей цепи, соединяющей

вершины (i, j). Первоначально за длину кратчайшей цепи

между i и j принимается длина дуги (i, j), соединяющей эти

узлы. Затем последовательно проверяются всевозможные

промежуточные вершины, расположенные между i и j. Если

длина цепи, проходящей через некоторую промежуточную

вершину меньше текущего значения dij, то переменной dij

присваивается новое значение. Данная процедура повторяется

для всевозможных пар узлов, пока не будут получены все

значения d*ij.

Фигура 2. Основная операция в алгоритме Флойда.

Определяется будет ли путь из вершины i в j через вершину k

короче, чем прямой путь из i в j.

Алгоритм Флойда позволяет решить задачу о нахождении

кратчайших путей для сети из n вершин за n итераций.

Обозначим dij( l ) оценку длины кратчайшей цепи из вершины

Page 27: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

i в j полученную на l - й итерации, тогда ее получение может

быть определено следующей операцией

dij( l) = mindij( l-1);dil (l-1) + dlj( l-1) (1).

Если операцию (1) выполнить с данной парой узлов i и j и

всеми узлами l в порядке возрастания номеров l, то значение

dij( n ) полученное на последней итерации, будет равно длине

кратчайшей цепи из узла i в узел j.

Реализация последовательного алгоритма Флойда приведена

в следующей функции matrd.

#include<stdio.h>

#include<stdlib.h>

#define maxs 100

int d[maxs][maxs];

void matrd(int n)

int i,j,k;

for(l=0;l<n;l++)

for(i=0;i<n;i++)

for(j=0;j<n;j++)

if(d[i][j] > (d[i][l]+d[l][j]))

d[i][j]= d[i][l]+d[l][j];

Backtracking Полный перебор.

Игры.

«Крестики-нолики».

Page 28: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Дерево игры: корень – исходное состояние доски, каждый узел – след.позиция,

листья – позиции, из которых невозможен ход (выигрыш или отсутствие

пустых клеток). Каждому узлу назначается опр. цена. Сначала – листьям

1(выигрыш 1-го), 0 (ничья),-1(выигрыш 2-го), затем – вышележащим по

порядку.

Каждый узел такого дерева представляет определенную позицию на доске.

Начальная позиция соответствует корню дерева. Если позиция х ассоциируется

с узлом п, тогда потомки узла п соответствуют совокупности допустимых ходов

из позиции х, и с каждым потомком ассоциируется соответствующая

результирующая позиция на доске. Например, на рис. 10.12 показана часть

дерева для игры в "крестики-нолики".

Листья этого дерева соответствуют таким позициям на доске, из которых невоз-

можно сделать ход, — то ли потому, что кто-то из игроков уже одержал победу,

то ли потому, что все клетки заполнены и игра закончилась вничью. Каждому

узлу дерева соответствует определенная цена. Сначала назначается цены

листьям. Допустим, речь идет об игре в "крестики-нолики". В таком случае

листу назначается цена -1,0 или 1 в зависимости от того, соответствует ли

данной позиции проигрыш, ничья или выигрыш игрока 1 (который ставит

"крестики").

Эти цены распространяются вверх по дереву в соответствии со следующим

правилом. Если какой-либо узел соответствует такой позиции, из которой

должен сделать ход игрок 1, тогда соответствующая цена является

максимальной среди цен потомков данного узла. При этом предполагаем, что

игрок 1 сделает самый выгодный для себя ход, т.е. такой, который принесет ему

самый ценный результат. Если же узел соответствует ходу итрока 2, тогда

соответствующая цена является минимальной среди цен потомков данного

узла. При этом мы предполагаем, что игрок 2 также сделает самый выгодный

для себя ход, т.е. такой, который при самом благоприятном исходе приведет к

проигрышу игрока 1, а при менее предпочтительном исходе — к ничьей. Пример 10.6. На рис. 10.12 показаны цены позиций в игре "крестики-нолики".

Листьям, которые приносят выигрыш для игрока О (который рисует "нолики"),

назначается цена -1; листьям, которые приносят ничью, назначается цена 0; а

листьям, которые приносят выигрыш для игрока Х - +1.

Page 29: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Function search (B:boardtype; mode:modetype)^real;

Var C:boardtype;

Value:real;

Begin

If B – leaf then

Search=payoff(B); exit;

Else

Begin

If mode=MAX then Value:=-8

Else Value:=8

for every sone C of B do

if mode=MAX

then Value:=max(Value, Search(C,MIN))

else Value:=min(Value, Search(C,MAX));

Search= Value;

End;

End.

Альфа-бета отсечение

Page 30: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Конечное значение – «выигрыш».

Ориентировочное значение – верхний предел в режиме MAX, нижний - в MIN.

Оценка дерева:

1. Если рассмотрели или осекли всех потомков узла n, сделать

ориентировочное значение конечным.

2. Если ориентировочное значение узла n в режиме MAX =v1 , а конечное

значение одного из потомков =v2 , то установить ориентировочное

значение = MAX (v1 , v2), в режиме MIN – наоборот.

3. Если p является узлом в режиме MIN с ор.значением v1, имеет родителя q

в режиме MAX с ор.значением v2, причем v1 <= v2, то можно отсечь

Одно простое условие позволяет нам избавиться от рассмотрения значительной

ти типичного дерева игры. Вернемся к эскизу программы, представленному в

лиси ге 10,3. Цикл for в строке (6) может проигнорировать определенных

сыновей — нередко довольно большое их число. Допустим, мы рассматриваем

узел п, показанный в рис. 10.13, и уже определили, что цена Ci первого из

сыновей узла п равняется 20. IL скольку узел п находится в режиме МАХ (т.е.

ход 1-го игрока), то его значение меньше 20. Допустим теперь, что, продолжая

поиск, мы нашли, что у сына с2 есть томок d с выигрышем 15. Поскольку узел

е2 находится в режиме MIN (т.е. ход 2-го и рока), то значение узла с2 не может

быть больше 15. Таким образом, какое бы ни бь значение узла с2, оно не может

влиять на цену узла п и любого предка узла п.

Таким образом, в ситуации, показанной на рис. 10.13, можно проигнорировать

рассмотрение тех потомков узла с2, которые мы еще не рассматривали. Общее

Page 31: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

правило пропуска или "отсечения" узлов связано с понятием конечных и

ориентировочных значений для узлов. Конечное значение — это то, что

мы просто называем "значением" (выигрышем). Ориентировочное значение

— это верхний предел значений узлов в режиме MIN или нижний предел

значений узлов в режиме МАХ. Ниже перечислены правила вычисления

конечных и ориентировочных значений. 1. Если мы уже рассмотрели или отсекли всех потомков узла п, сделать

ориентировочное значение узла п конечным значением. 2. Если ориентировочное значение узла п в режиме МАХ равно Uj, а конечное

значение одного из его потомков равняется 1)%, тогда установить

ориентировочное значение узла п равным max(i>i, u2). Если же узел п находится

в режиме M1N, тогда ориентировочное значение узла п установить равным

min(i'1, y2). 3. Если р является узлом в режиме MIN, имеет родителя q (в режиме МАХ), а

ориентировочные значения узлов р и q равняются v1 и v2 соответственно,

причем v1 <= v2, тогда можно отсечь всех нерассмотренных потомков узла р.

Можно также отсечь нерассмотренных потомков узла р, если р является узлом

в режиме МАХ, a q является, таким образом, узлом в режиме MIN, и v1 >= v2. Пример 10.7. Рассмотрим дерево, показанное на рис. 10.14. Полагая, что

значения листьев соответствуют значениям, указанным на рисунке, мы хотим

вычислить значение корня. Начинаем обход дерева в обратном порядке.

Достигнув узла D, в соответствии с правилом (2) назначаем узлу С

ориентировочное значение 2, которое является конечным значение узла D.

Просматриваем узел Е и возвращаемся в узел С, а затем переходим в узел В. В

соответствии с правилом (1) конечное значение узла С равно 2, а ориентиро-

вочное значение узла В — 2. Обход далее продолжается вниз к узлу G, а затем

обратно в узел F. Ориентировочное значение узла F равно 6. В соответствии с

правилом (3) можно отсечь узел Н, поскольку ориентировочное значение узла F

уменьшиться не может и оно уже больше значения узла В, которое не может

увеличиться.

Page 32: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Продолжим пример. Для узла А назначаем ориентировочное значение 2 и

переходим к узлу К. Для узла J назначается ориентировочное значение 8.

Значение узла L не влияет на значение узла J. Для узла I назначается

ориентировочное значение 8. Переходим в узел N, узлу М назначается

ориентировочное значение 5. Необходимо выполнить просмотр узла О,

поскольку 5 (ориентировочное значение узла М) меньше, чем ориентировочное

значение узла I. Далее пересматриваются ориентировочные значения узлов / и

А. Переходим к узлу R. Выполняется просмотр узлов R и S, узлу Р назначается

ориентировочное значение 4. Просмотр узла Т и всех его потомков проводить

не нужно, поскольку это может только понизить значение узла Р, которое уже и

без того слишком низкое, чтобы повлиять на значение узлаА.

Метод ветвей и границ

Backtracking можно применять для любого вида задач, связанных с поиском

оптимальной конфигурации того или иного типа. строится дерево

возможностей: узлы – конфигурации, потомки – подмножества конфигураций,

листья – решения задачи. Листья оцениваются и выбирается оптимальное

решение.

Пример: задача коммивояжера. Корень – все маршруты. Сыновья –

содержащий определенное ребро и не содержащий. Обходим в

лексикографическом порядке. Добавляем не все ребра – степень каждой

вершины должна=2.

Page 33: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Метод ветвей и границ:

1. Оценивается нижняя граница стоимости любого решения, входящего в

подмножество для узла n

2. Если наилучшая из найденных к текущему моменту стоит меньше, чем

граница из 1, то поддерево n можно не анализировать.

Оценка: сумма стоимости 2-х ребер, инцидентных узлу n, >=суммы

инцидентных узлу n ребер с наименьшей стоимостью => стоимость любого

маршрута >= ½ таких сумм по всем n.

Поиск локального оптимума

Описанная ниже стратегия нередко приводит к оптимальному решению

задачи. 1. Начните с произвольного решения.

2. Для улучшения текущего решения примените к нему какое-либо

преобразование из некоторой заданной совокупности преобразований.

Это улучшенное решение становится новым "текущим" решением.

Page 34: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

3. Повторяйте указанную процедуру до тех пор, пока ни одно из

преобразований в заданной их совокупности не позволит улучшить

текущее решение.

Результирующее решение может, хотя и необязательно, оказаться

оптимальным. В принципе, если "заданная совокупность преобразований"

включает все преобразования, которые берут в качестве исходного одно

решение и заменяют его каким-либо другим, процесс "улучшений" не

закончится до тех пор, пока мы не получим оптимальное решение. Но в таком

случае время выполнения пункта (2) окажется таким же, как и время,

требующееся для анализа всех решений, поэтому описываемый подход в целом

окажется достаточно бессмысленным. Этот метод имеет смысл лишь в том случае, когда мы можем ограничить

нашу совокупность преобразований небольшим ее подмножеством, что дает

возможность выполнить все преобразования за относительно короткое время:

если "размер" задачи равняется п, то мы можем допустить О(п2) или О(п)

преобразований. Если совокупность преобразований невелика, естественно

рассматривать решения, которые можно преобразовывать одно в другое за один

шаг, как "близкие". Такие преобразования называются "локальными", а

соответствующий метод называется локальным поиском. Пример 10.11. Одной из задач, которую можно решить именно методом

локального поиска, является задача нахождения минимального остовного

дерева. Локальными преобразованиями являются такие преобразования, в ходе

которых мы берем то или иное ребро, не относящееся к текущему остовному

дереву, добавляем его в это дерево (в результате мы должны получить цикл), а

затем убираем из этого цикла в точности одно ребро (предположительно, ребро

с наивысшей стоимостью), чтобы образовать новое дерево.

Рассмотрим, например, граф на рис. 10.16. Мы можем начать с дерева,

показанного на рис. 10.18,а. Одно из преобразований, которые можно было бы

выполнить, заключается в добавлении ребра (d, e) и устранении из

образовавшегося цикла (е, а, с, d, e) какого-либо другого ребра. Если мы

удалим ребро (а, е), то уменьшим стоимость дерева с 20 до 19. Это

преобразование можно выполнить, получив в результате дерево (рис. 10.18,6), к

Page 35: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

которому мы опять попытаемся применить улучшающее преобразование. Одно

из таких преобразований сводится к вставке ребра (a, d) и удалению из

образовавшегося цикла ребра (с, d). Результат этого преобразования показан на

рис. 10.18,в. Затем можно вставить ребро (а, b) и убрать ребро (b, с), как

показано на рис. 10.18,г, а потом — вставить ребро (b, е) вместо ребра (d, e).

Результирующее дерево (рис. 10.18,д) является минимальным. Мы можем

убедиться в том, что каждое ребро, не входящее в состав этого дерева, имеет

наивысшую стоимость среди всех ребер в цикле, который они с этим ребром

составляют. Таким образом, к дереву на рис. 10.18,г преобразования уже

неприменимы. Время, которое занимает выполнение алгоритма в примере 10.11 на графе

из п узлов и е ребер, зависит от количества требующихся улучшений решения.

Одна лишь проверка того факта, что преобразования уже неприменимы, может

занять О(пе) времени, поскольку для этого необходимо перебрать е ребер, а

каждое из них может образовать цикл длиной примерно п. Таким образом, этот

алгоритм несколько хуже, чем алгоритмы Прима и Крускала, однако он может

служить примером получения оптимального решения на основе локального

поиска.

Локальные и глобальные оптимальные решения

Алгоритмы локального поиска проявляют себя с наилучшей стороны как

эвристические алгоритмы для решения задач, точные решения которых

требуют экспоненциальных затрат времени. Общепринятый метод поиска

состоит в cлeдующем. Начать следует с ряда произвольных решений, применяя

к каждому из них локальные преобразования до тех пор, пока не будет

получено локально-оптимальное решение, т.е. такое, которое не сможет

улучшить ни одно преобразование. Как показано на рис. 10.19, на основе

Page 36: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

большинства (или даже всех) произвольных начальных решений мы нередко

будем получать разные локально-оптимальные решения. Если нам повезет,

одно из них окажется глобально-оптимальным, т.е. лучше любого другого

решения. На практике мы можем и не найти глобально-оптимального решения,

показанного на рис. 10.19, поскольку количество локально-оптимальных

решений может оказаться колоссальным. Однако мы можем по крайней мере

выбрать локально-оптимальное решение, имеющее минимальную стоимость

среди всех найденных нами решений. Поскольку количество видов локальных

преобразований, использующихся для решения различных задач, очень велико,

мы завершим этот раздел описанием задачи коммивояжера. Задача коммивояжера

Методы локального поиска особенно хорошо подходят для решения

задачи коммивояжера. Простейшим преобразованием, которым можно в этом

случае воспользоваться, является так называемый "двойной выбор". Он

заключается в том, что мы выбираем любые два ребра, например ребра (А, В) и

(С, D), показанные на рис. 10.20, удаляем их и "перекоммутируем"

соединявшиеся ими точки так, чтобы образовался новый маршрут. На рис.

10.20 этот новый маршрут начинается в точке В, продолжается по часовой

стрелке до С, проходит по ребру (С, А), затем — против часовой стрелки от А к

D и наконец по ребру (D, В). Если сумма длин (А, С) и (В, D) оказывается

меньше суммы длин (А, В) и (С, D), значит, нам удалось получить улучшенный

маршрут. Обратите внимание, что мы не можем соединить точки А и D, В и С,

поскольку полученный результат будет являться не маршрутом, а двумя

изолированными друг от друга циклами.

Page 37: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Вас не должен вводить в заблуждение рис. 10.20. Действительно, если длины ребер

являются расстояниями на плоскости, тогда ребра, показанные пунктирными линиями на

этом рисунке, должны быть длиннее ребер, которые мы удалили. Однако, вообще говоря, нет

никаких оснований предполагать, что расстояния, показанные на рис. 10.20, обязательно

должны быть евклидовыми расстояниями, но если они и являются таковыми, то

пересекающимися могли бы быть ребра (А, В) и (С, D), а не (А, С) и (В, D).

Чтобы найти локально-оптимальный маршрут, мы начинаем с какого-

либо произвольного маршрута и рассматриваем все пары несмежных ребер,

такие как (А, В) и (С, D) на рис. 10.20. Если данный маршрут можно улучшить

путем замены этих ребер на (А, С) и (В, D), это нужно сделать, а затем

продолжить рассмотрение оставшихся пар ребер. Обратите внимание, что

каждое из новых ребер (А, С) и (В, D), должно образовать пару со всеми

другими ребрами данного маршрута, результатом чего могут явиться

дополнительные улучшения. Пример 10.12. Вернемся к рис. 10.16 и допустим, что в качестве

исходного выбран маршрут, показанный на рис. 10.21,а. Ребра (а, е) и (с, d)

Page 38: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

общей стоимостью 12 можно заменить ребрами (а, d) и (с, е) общей стоимостью

10, как показано на рис. 10.21,6. Затем ребра (а, b) и (с, е) можно заменить на

ребра (а, с) и (b, е), что обеспечило бы нам оптимальный маршрут, показанный

на рис. 10.21,в. Легко убедиться, что на этом рисунке нельзя удалить ни одну

пару ребер, выгодно заменив ее пересекающимися ребрами с теми же

конечными точками. Возьмем хотя бы один пример: ребра (b, с) и (d, e) вместе

имеют относительно высокую стоимость — 10. Но (с, е) и (b, d) еще хуже,

поскольку их совместная стоимость равна 14.

Двойной выбор можно обобщить как выбор k элементов для любого

постоянного k. В этом случае мы удаляем до k ребер и "перекоммутируем"

оставшиеся элементы в любом порядке, пытаясь получить какой-либо маршрут.

Обратите внимание: мы не требуем, чтобы удаленные ребра вообще были

несмежными, хотя в случае двойного выбора не было никакого смысла

рассматривать удаление двух смежных ребер. Обратите также внимание, что

при k > 2 существует несколько способов соединения частей графа. На рис.

10.22 представлен процесс тройного выбора с помощью любой из

перечисленных ниже восьми совокупностей ребер.

Легко убедиться в том, что для фиксированного k количество различных

преобразований при k-выборе, которые необходимо рассмотреть при наличии п

вершин, равно О(пк). Например, при k = 2 точное количество таких

преобразований равно п(п - 3)/2. Однако время, которое требуется для

получения какого-либо из локально-оптимальных маршрутов, может оказаться

значительно больше этой величины, поскольку для получения этого локально-

оптимального маршрута надо выполнить довольно много локальных

Page 39: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

преобразований, а каждое улучшающее преобразование связано с введением

новых ребер, которые могут участвовать в последующих преобразованиях и

еще больше улучшают данный маршрут. Показано, что с практической точки

зрения "выбор с переменной глубиной" (т.е. выбор с разными значениями k на

разных этапах) является чрезвычайно эффективным методом и с большой

вероятностью обеспечивает получение оптимального маршрута для задач

коммивояжера с 40—100 городами.

Page 40: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

6. Проектирование параллельных алгоритмов

Методология проектирования

Разделение

Установление связей

Агрегирование

Привязка к конкретной ЭВМ

Пример: матричные вычисления

Являясь вычислительно трудоемкими, матричные вычисления представляют

собой классическую область применения параллельных вычислений. С одной

стороны, использование высокопроизводительных многопроцессорных систем

позволяет существенно повысить сложность решаемых задач. С другой

стороны, в силу своей достаточно простой формулировки матричные операции

предоставляют прекрасную возможность для демонстрации многих приемов и

методов параллельного программирования.

В данной лекции обсуждаются методы параллельных вычислений для операции

матрично-векторного умножения. При изложении следующего материала

будем полагать, что рассматриваемые матрицы являются плотными (dense), то

есть число нулевых элементов в них незначительно по сравнению с общим

количеством элементов матриц.

6.1. Принципы распараллеливания

Для многих методов матричных вычислений характерным является повторение

одних и тех же вычислительных действий для разных элементов матриц.

Данное свойство свидетельствует о наличии параллелизма по данным при

выполнении матричных расчетов, и, как результат, распараллеливание

матричных операций сводится в большинстве случаев к разделению

обрабатываемых матриц между процессорами используемой вычислительной

системы. Выбор способа разделения матриц приводит к определению

конкретного метода параллельных вычислений; существование разных схем

распределения данных порождает целый ряд параллельных алгоритмов

матричных вычислений.

Наиболее общие и широко используемые способы разделения матриц состоят в

разбиении данных на полосы (по вертикали или горизонтали) или на

прямоугольные фрагменты (блоки).

Page 41: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1. Ленточное разбиение матрицы. При ленточном (block-striped) разбиении

каждому процессору выделяется то или иное подмножество строк (rowwise или

горизонтальное разбиение) или столбцов (columnwise или вертикальное

разбиение) матрицы (рис. 6.1). Разделение строк и столбцов на полосы в

большинстве случаев происходит на непрерывной (последовательной) основе.

При таком подходе для горизонтального разбиения по строкам, например,

матрица A представляется в виде (см. рис. 6.1)

(6.1)

где ai=(ai1,ai2,...,ain), 0 i<m, есть i-я строка матрицы A (предполагается, что

количество строк m кратно числу процессоров p, т.е. m = k·p). Во всех

алгоритмах матричного умножения и умножения матрицы на вектор, которые

будут рассмотрены в этой и следующей лекциях, применяется разделение

данных на непрерывной основе.

Другой возможный подход к формированию полос состоит в применении той

или иной схемы чередования (цикличности) строк или столбцов. Как правило,

для чередования используется число процессоров p – в этом случае при

горизонтальном разбиении матрица A принимает вид

(6.2)

Циклическая схема формирования полос может оказаться полезной для лучшей

балансировки вычислительной нагрузки процессоров (например, при решении

системы линейных уравнений с использованием метода Гаусса – см. лекцию 8).

2. Блочное разбиение матрицы. При блочном (chessboard block) разделении

матрица делится на прямоугольные наборы элементов – при этом, как правило,

используется разделение на непрерывной основе. Пусть количество

процессоров составляет p = s·q, количество строк матрицы является кратным s,

а количество столбцов – кратным q, то есть m = k·s и n = l·q. Представим

исходную матрицу A в виде набора прямоугольных блоков следующим

образом:

где Aij — блок матрицы, состоящий из элементов:

(6.3)

Page 42: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

При таком подходе целесообразно, чтобы вычислительная система имела

физическую или, по крайней мере, логическую топологию процессорной

решетки из s строк и q столбцов. В этом случае при разделении данных на

непрерывной основе процессоры, соседние в структуре решетки, обрабатывают

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

блочной схемы может быть применено циклическое чередование строк и

столбцов.

В данной лекции рассматриваются три параллельных алгоритма для умножения

квадратной матрицы на вектор. Каждый подход основан на разном типе

распределения исходных данных (элементов матрицы и вектора) между

процессорами. Разделение данных меняет схему взаимодействия процессоров,

поэтому каждый из представленных методов существенным образом

отличается от двух остальных.

Рис. 6.1. Способы распределения элементов матрицы между процессорами

вычислительной системы 6.2. Постановка задачи

В результате умножения матрицы А размерности m × n и вектора b, состоящего

из n элементов, получается вектор c размера m, каждый i-й элемент которого

есть результат скалярного умножения i-й строки матрицы А (обозначим эту

строчку ai) и вектора b:

(6.4)

Тем самым получение результирующего вектора c предполагает повторение m

однотипных операций по умножению строк матрицы A и вектора b. Каждая

такая операция включает умножение элементов строки матрицы и вектора b (n

операций) и последующее суммирование полученных произведений (n-1

операций). Общее количество необходимых скалярных операций есть величина

T1=m·(2n-1)

Page 43: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

6.3. Последовательный алгоритм

Последовательный алгоритм умножения матрицы на вектор может быть

представлен следующим образом.

Алгоритм 6.1. Последовательный алгоритм умножения матрицы на вектор

// Алгоритм 6.1

// Поcледовательный алгоритм умножения матрицы на вектор

for (i = 0; i < m; i++)

c[i] = 0;

for (j = 0; j < n; j++)

c[i] += A[i][j]*b[j]

Матрично-векторное умножение – это последовательность вычисления

скалярных произведений. Поскольку каждое вычисление скалярного

произведения векторов длины n требует выполнения n операций умножения и

n-1 операций сложения, его трудоемкость порядка O(n). Для выполнения

матрично-векторного умножения необходимо осуществить m операций

вычисления скалярного произведения, таким образом, алгоритм имеет

трудоемкость порядка O(mn).

6.4. Разделение данных

При выполнении параллельных алгоритмов умножения матрицы на вектор,

кроме матрицы А, необходимо разделить еще вектор b и вектор результата c.

Элементы векторов можно продублировать, то есть скопировать все элементы

вектора на все процессоры, составляющие многопроцессорную

вычислительную систему, или разделить между процессорами. При блочном

разбиении вектора из n элементов каждый процессор обрабатывает

непрерывную последовательность из k элементов вектора (мы предполагаем,

что размерность вектора n нацело делится на число процессоров, т.е. n= k·p).

Поясним, почему дублирование векторов b и c между процессорами является

допустимым решением (далее для простоты изложения будем полагать, что

m=n). Векторы b и с состоят из n элементов, т.е. содержат столько же данных,

сколько и одна строка или один столбец матрицы. Если процессор хранит

строку или столбец матрицы и одиночные элементы векторов b и с, то общее

число сохраняемых элементов имеет порядок O(n). Если процессор хранит

строку (столбец) матрицы и все элементы векторов b и с, то общее число

Page 44: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

сохраняемых элементов также порядка O(n). Таким образом, при дублировании

и при разделении векторов требования к объему памяти из одного класса

сложности.

6.5. Умножение матрицы на вектор при разделении данных по строкам

Рассмотрим в качестве первого примера организации параллельных матричных

вычислений алгоритм умножения матрицы на вектор, основанный на

представлении матрицы непрерывными наборами (горизонтальными полосами)

строк. При таком способе разделения данных в качестве базовой подзадачи

может быть выбрана операция скалярного умножения одной строки матрицы на

вектор.

6.5.1. Выделение информационных зависимостей

Для выполнения базовой подзадачи скалярного произведения процессор

должен содержать соответствующую строку матрицы А и копию вектора b.

После завершения вычислений каждая базовая подзадача определяет один из

элементов вектора результата c.

Для объединения результатов расчета и получения полного вектора c на

каждом из процессоров вычислительной системы необходимо выполнить

операцию обобщенного сбора данных (см. лекцию 4), в которой каждый

процессор передает свой вычисленный элемент вектора c всем остальным

процессорам. Этот шаг можно выполнить, например, с использованием

функции MPI_Allgather из библиотеки MPI.

В общем виде схема информационного взаимодействия подзадач в ходе

выполняемых вычислений показана на рис. 6.2.

Рис. 6.2. Организация вычислений при выполнении параллельного алгоритма

умножения матрицы на вектор, основанного на разделении матрицы по строкам

6.5.2. Масштабирование и распределение подзадач по процессорам

Page 45: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

В процессе умножения плотной матрицы на вектор количество

вычислительных операций для получения скалярного произведения одинаково

для всех базовых подзадач. Поэтому в случае когда число процессоров p

меньше числа базовых подзадач m, мы можем объединить базовые подзадачи

таким образом, чтобы каждый процессор выполнял несколько таких задач,

соответствующих непрерывной последовательности строк матрицы А. В этом

случае по окончании вычислений каждая базовая подзадача определяет набор

элементов результирующего вектора с.

Распределение подзадач между процессорами вычислительной системы может

быть выполнено произвольным образом.

6.5.3. Анализ эффективности

Для анализа эффективности параллельных вычислений здесь и далее будут

строиться два типа оценок. В первой из них трудоемкость алгоритмов

оценивается в количестве вычислительных операций, необходимых для

решения поставленной задачи, без учета затрат времени на передачу данных

между процессорами, а длительность всех вычислительных операций считается

одинаковой. Кроме того, константы в получаемых соотношениях, как правило,

не указываются — для первого типа оценок важен прежде всего порядок

сложности алгоритма, а не точное выражение времени выполнения

вычислений. Как результат, в большинстве случаев подобные оценки

получаются достаточно простыми и могут быть использованы для начального

анализа эффективности разрабатываемых алгоритмов и методов.

Второй тип оценок направлен на формирование как можно более точных

соотношений для предсказания времени выполнения алгоритмов. Получение

таких оценок проводится, как правило, при помощи уточнения выражений,

полученных на первом этапе. Для этого в имеющиеся соотношения вводятся

параметры, задающие длительность выполнения операций, строятся оценки

трудоемкости коммуникационных операций, указываются все необходимые

константы. Точность получаемых выражений проверяется при помощи

вычислительных экспериментов, по результатам которых время выполненных

расчетов сравнивается с теоретически предсказанными оценками

длительностей вычислений. Как результат, оценки подобного типа имеют, как

правило, более сложный вид, но позволяют более точно оценивать

эффективность разрабатываемых методов параллельных вычислений.

Рассмотрим трудоемкость алгоритма умножения матрицы на вектор. В случае

если матрица А квадратная (m=n), последовательный алгоритм умножения

матрицы на вектор имеет сложность T1=n2. В случае параллельных вычислений

Page 46: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

каждый процессор производит умножение только части (полосы) матрицы A на

вектор b, размер этих полос равен n/p строк. При вычислении скалярного

произведения одной строки матрицы и вектора необходимо произвести n

операций умножения и (n-1) операций сложения. Следовательно,

вычислительная трудоемкость параллельного алгоритма определяется

выражением:

(6.5)

С учетом этой оценки показатели ускорения и эффективности параллельного

алгоритма имеют вид:

(6.6)

Построенные выше оценки времени вычислений выражены в количестве

операций и, кроме того, определены без учета затрат на выполнение операций

передачи данных. Используем ранее высказанные предположения о том, что

выполняемые операции умножения и сложения имеют одинаковую

длительность τ. Кроме того, будем предполагать также, что вычислительная

система является однородной, т.е. все процессоры, составляющие эту систему,

обладают одинаковой производительностью. С учетом введенных

предположений время выполнения параллельного алгоритма, связанное

непосредственно с вычислениями, составляет

(здесь и далее операция есть округление до целого в большую сторону).

Оценка трудоемкости операции обобщенного сбора данных уже выполнялась в

лекции 4 (см. п. 4.3.4). Как уже отмечалась ранее, данная операция может быть

выполнена за log2p итераций1)

. На первой итерации взаимодействующие

пары процессоров обмениваются сообщениями объемом (w есть размер

одного элемента вектора c в байтах), на второй итерации этот объем

увеличивается вдвое и оказывается равным и т.д. Как результат,

длительность выполнения операции сбора данных при использовании модели

Хокни может быть определена при помощи следующего выражения

(6.7)

Page 47: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

где – латентность сети передачи данных, β – пропускная способность сети.

Таким образом, общее время выполнения параллельного алгоритма составляет

(6.8)

(для упрощения выражения в (6.8) предполагалось, что значения n/p и log2p

являются целыми).

6.5.4. Программная реализация

Представим возможный вариант параллельной программы умножения матрицы

на вектор с использованием алгоритма разбиения матрицы по строкам. При

этом реализация отдельных модулей не приводится, если их отсутствие не

оказывает влияние на понимании общей схемы параллельных вычислений.

1. Главная функция программы. Реализует логику работы алгоритма,

последовательно вызывает необходимые подпрограммы.

// Программа 6.1

// Умножение матрицы на вектор – ленточное горизонтальное

разбиение

// (исходный и результирующий векторы дублируются между

процессами)

void main(int argc, char* argv[])

double* pMatrix; // Первый аргумент – исходная матрица

double* pVector; // Второй аргумент – исходный вектор

double* pResult; // Результат умножения матрицы на

вектор

int Size; // Размеры исходных матрицы и вектора

double* pProcRows;

double* pProcResult;

int RowNum;

double Start, Finish, Duration;

MPI_Init(&argc, &argv);

MPI_Comm_size(MPI_COMM_WORLD, &ProcNum);

MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);

// Выделение памяти и инициализация исходных данных

ProcessInitialization(pMatrix, pVector, pResult,

pProcRows,

pProcResult, Size, RowNum);

// Распределение исходных данных между процессами

DataDistribution(pMatrix, pProcRows, pVector, Size,

RowNum);

Page 48: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

// Параллельное выполнение умножения матрицы на вектор

ParallelResultCalculation(pProcRows, pVector,

pProcResult,Size, RowNum);

// Сбор результирующего вектора на всех процессах

ResultReplication(pProcResult, pResult, Size, RowNum);

// Завершение процесса вычислений

ProcessTermination(pMatrix, pVector, pResult,

pProcRows,

pProcResult);

MPI_Finalize();

2. Функция ProcessInitialization. Эта функция задает размер и элементы для

матрицы A и вектора b. Значения для матрицы A и вектора b определяются в

функции RandomDataInitialization.

// Функция для выделения памяти и инициализации исходных

данных

void ProcessInitialization (double* &pMatrix, double*

&pVector,

double* &pResult, double* &pProcRows, double*

&pProcResult,

int &Size, int &RowNum)

int RestRows; // Количество строк матрицы, которые еще

// не распределены

int i;

if (ProcRank == 0)

do

printf("\nВведите размер матрицы: ");

scanf("%d", &Size);

if (Size < ProcNum)

printf("Размер матрицы должен превышать

количество процессов! \n ");

while (Size < ProcNum);

MPI_Bcast(&Size, 1, MPI_INT, 0, MPI_COMM_WORLD);

RestRows = Size;

for (i=0; i<ProcRank; i++)

Page 49: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

RestRows = RestRows-RestRows/(ProcNum-i);

RowNum = RestRows/(ProcNum-ProcRank);

pVector = new double [Size];

pResult = new double [Size];

pProcRows = new double [RowNum*Size];

pProcResult = new double [RowNum];

if (ProcRank == 0)

pMatrix = new double [Size*Size];

RandomDataInitialization(pMatrix, pVector, Size);

3. Функция DataDistribution. Осуществляет рассылку вектора b и

распределение строк исходной матрицы A по процессам вычислительной

системы. Следует отметить, что когда количество строк матрицы n не является

кратным числу процессоров p, объем пересылаемых данных для процессов

может оказаться разным и для передачи сообщений необходимо использовать

функцию MPI_Scatterv библиотеки MPI.

// Функция для распределения исходных данных между

процессами

void DataDistribution(double* pMatrix, double* pProcRows,

double* pVector, int Size, int RowNum)

int *pSendNum; // Количество элементов, посылаемых

процессу

int *pSendInd; // Индекс первого элемента данных,

// посылаемого процессу

int RestRows=Size; // Количество строк матрицы,

которые еще

// не распределены

MPI_Bcast(pVector, Size, MPI_DOUBLE, 0,

MPI_COMM_WORLD);

// Выделение памяти для хранения временных объектов

pSendInd = new int [ProcNum];

pSendNum = new int [ProcNum];

// Определение положения строк матрицы, предназначенных

// каждому процессу

RowNum = (Size/ProcNum);

Page 50: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

pSendNum[0] = RowNum*Size;

pSendInd[0] = 0;

for (int i=1; i<ProcNum; i++)

RestRows -= RowNum;

RowNum = RestRows/(ProcNum-i);

pSendNum[i] = RowNum*Size;

pSendInd[i] = pSendInd[i-1]+pSendNum[i-1];

// Рассылка строк матрицы

MPI_Scatterv(pMatrix, pSendNum, pSendInd, MPI_DOUBLE,

pProcRows,

pSendNum[ProcRank], MPI_DOUBLE, 0, MPI_COMM_WORLD);

// Освобождение памяти

delete [] pSendNum;

delete [] pSendInd;

Следует отметить, что такое разделение действий генерации исходных данных

и их рассылки между процессами может быть неоправданным в реальных

параллельных вычислениях при большом объеме данных. Широко

используемый подход в таких случаях состоит в организации передачи

сообщений процессам сразу же после того, как данные процессов будут

сгенерированы. Снижение затрат памяти для хранения данных может быть

достигнуто также и за счет организации генерации данных в последнем

процессе (при таком подходе память для пересылаемых данных и для данных

процесса может быть одной и той же).

4. Функция ParallelResultCaculation. Данная функция производит умножение

на вектор тех строк матрицы, которые распределены на данный процесс, и

таким образом получается блок результирующего вектора с.

// Функция для вычисления части результирующего вектора

void ParallelResultCalculation(double* pProcRows, double*

pVector,

double* pProcResult, int Size, int RowNum)

int i, j;

for (i=0; i<RowNum; i++)

pProcResult[i] = 0;

for (j=0; j<Size; j++)

pProcResult[i] += pProcRows[i*Size+j]*pVector[j];

Page 51: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

5. Функция ResultReplication. Объединяет блоки результирующего вектора с,

полученные на разных процессах, и копирует вектор результата на все

процессы вычислительной системы.

// Функция для сбора результирующего вектора на всех

процессах

void ResultReplication(double* pProcResult, double*

pResult,

int Size, int RowNum)

int *pReceiveNum; // Количество элементов, посылаемых

процессом

int *pReceiveInd; // Индекс элемента данных в

результирующем

// векторе

int RestRows=Size; // Количество строк матрицы, которые

еще не

// распределены

int i;

// Выделение памяти для временных объектов

pReceiveNum = new int [ProcNum];

pReceiveInd = new int [ProcNum];

// Определение положения блоков результирующего вектора

pReceiveInd[0] = 0;

pReceiveNum[0] = Size/ProcNum;

for (i=1; i<ProcNum; i++)

RestRows -= pReceiveNum[i-1];

pReceiveNum[i] = RestRows/(ProcNum-i);

pReceiveInd[i] = pReceiveInd[i-1]+pReceiveNum[i-1];

// Сбор всего результирующего вектора на всех процессах

MPI_Allgatherv(pProcResult, pReceiveNum[ProcRank],

MPI_DOUBLE, pResult, pReceiveNum, pReceiveInd,

MPI_DOUBLE, MPI_COMM_WORLD);

// Освобождение памяти

delete [] pReceiveNum;

delete [] pReceiveInd;

Page 52: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

6.5.5. Результаты вычислительных экспериментов

Рассмотрим результаты вычислительных экспериментов, выполненных для

оценки эффективности приведенного выше параллельного алгоритма

умножения матрицы на вектор. Кроме того, используем полученные результаты

для сравнения теоретических оценок и экспериментальных показателей

времени вычислений и проверим тем самым точность полученных

аналитических соотношений. Эксперименты проводились на вычислительном

кластере Нижегородского университета на базе процессоров Intel Xeon 4

EM64T, 3000 МГц и сети Gigabit Ethernet под управлением операционной

системы Microsoft Windows Server 2003 Standard x64 Edition и системы

управления кластером Microsoft Compute Cluster Server (см. п. 1.2.3).

Определение параметров теоретических зависимостей (величин τ, w, , β)

осуществлялось следующим образом. Для оценки длительности τ базовой

скалярной операции проводилось решение задачи умножения матрицы на

вектор при помощи последовательного алгоритма и полученное таким образом

время вычислений делилось на общее количество выполненных операций – в

результате подобных экспериментов для величины τ было получено значение

1,93 нсек. Эксперименты, выполненные для определения параметров сети

передачи данных, показали значения латентности и пропускной способности β

соответственно 47 мкс и 53,29 Мбайт/с. Все вычисления производились над

числовыми значениями типа double, т.е. величина w равна 8 байт.

Результаты вычислительных экспериментов приведены в таблице 6.1.

Эксперименты проводились с использованием двух, четырех и восьми

процессоров. Времена выполнения алгоритмов указаны в секундах.

Таблица 6.1. Результаты вычислительных экспериментов для параллельного алгоритма

умножения матрицы на вектор при ленточной схеме разделения данных по строкам

Размер

матрицы

Последовательный

алгоритм

Параллельный алгоритм

2 процессора 4 процессора 8 процессоров

Время Ускорение Время Ускорение Время Ускорение

1000 0,0041 0,0021 1,8798 0,0017 2,4089 0,0175 0,2333

2000 0,016 0,0084 1,8843 0,0047 3,3388 0,0032 4,9443

3000 0,031 0,0185 1,6700 0,0097 3,1778 0,0059 5,1952

4000 0,062 0,0381 1,6263 0,0188 3,2838 0,0244 2,5329

5000 0,11 0,0574 1,9156 0,0314 3,4993 0,0150 7,3216

Page 53: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Сравнение экспериментального времени выполнения параллельного

алгоритма и теоретического времени Tp, вычисленного в соответствии с

выражением (6.8), представлено в таблице 6.2 и в графическом виде на рис. 6.3

и 6.4.

Таблица 6.2. Сравнение экспериментального и теоретического времени

выполнения параллельного алгоритма умножения матрицы на вектор,

основанного на разбиении матрицы по строкам

Размер объектов 2 процессора 4 процессора 8 процессоров

Tp T'p Tp T'p Tp T'p

1000 0,0069 0,0021 0,0108 0,0017 0,0152 0,0175

2000 0,0132 0,0084 0,0140 0,0047 0,0169 0,0032

3000 0,0235 0,0185 0,0193 0,0097 0,0196 0,0059

4000 0,0379 0,0381 0,0265 0,0188 0,0233 0,0244

5000 0,0565 0,0574 0,0359 0,0314 0,0280 0,0150

Рис. 6.3. График зависимости экспериментального T'p и теоретического Tp

времени выполнения параллельного алгоритма на двух процессорах от объема

исходных данных (ленточное разбиение матрицы по строкам)

Page 54: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Рис. 6.4. Зависимость ускорения от количества процессоров при выполнении

параллельного алгоритма умножения матрицы на вектор (ленточное разбиение

по строкам) для разных размеров матриц

6.6. Умножение матрицы на вектор при разделении данных по столбцам

Рассмотрим теперь другой подход к параллельному умножению матрицы на

вектор, основанный на разделении исходной матрицы на непрерывные наборы

(вертикальные полосы) столбцов.

6.6.1. Определение подзадач и выделение информационных зависимостей

При таком способе разделения данных в качестве базовой подзадачи может

быть выбрана операция умножения столбца матрицы А на один из элементов

вектора b. Для организации вычислений в этом случае каждая базовая

подзадача i, 0 i<n, должна содержать i-й столбец матрицы А и i-е элементы bi и

ci векторов b и с.

Параллельный алгоритм умножения матрицы на вектор начинается с того, что

каждая базовая задача i выполняет умножение своего столбца матрицы А на

элемент bi, в итоге в каждой подзадаче получается вектор c'(i) промежуточных

результатов. Далее для получения элементов результирующего вектора с

подзадачи должны обменяться своими промежуточными данными между собой

(элемент j, 0 j<n, частичного результата c'(i) подзадачи i, 0 i<n, должен быть

передан подзадаче j). Данная обобщенная передача данных (all-to-all

communication или total exchange) является наиболее общей коммуникационной

процедурой и может быть реализована при помощи функции MPI_Alltoall

библиотеки MPI. После выполнения передачи данных каждая базовая

Page 55: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

подзадача i, 0 i<n, будет содержать n частичных значений c'i(j), 0 j<n,

сложением которых и определяется элемент ci вектора результата с (см. рис.

6.5).

Рис. 6.5. Организация вычислений при выполнении параллельного алгоритма

умножения матрицы на вектор с использованием разбиения матрицы по

столбцам

6.6.2. Масштабирование и распределение подзадач по процессорам

Выделенные базовые подзадачи характеризуются одинаковой вычислительной

трудоемкостью и равным объемом передаваемых данных. В случае когда

количество столбцов матрицы превышает число процессоров, базовые

подзадачи можно укрупнить, объединив в рамках одной подзадачи несколько

соседних столбцов (в этом случае исходная матрица A разбивается на ряд

вертикальных полос). При соблюдении равенства размера полос такой способ

агрегации вычислений обеспечивает равномерность распределения

вычислительной нагрузки по процессорам, составляющим многопроцессорную

вычислительную систему.

Как и в предыдущем алгоритме, распределение подзадач между процессорами

вычислительной системы может быть выполнено произвольным образом.

6.6.3. Анализ эффективности

Пусть, как и ранее, матрица А является квадратной, то есть m=n. На первом

этапе вычислений каждый процессор умножает принадлежащие ему столбцы

матрицы А на элементы вектора b, после умножения полученные значения

суммируются для каждой строки матрицы А в отдельности

(6.9)

Page 56: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

(j0 и jl-1 есть начальный и конечный индексы столбцов базовой подзадачи i,

0 i<n). Поскольку размеры полосы матрицы А и блока вектора b равны n/p, то

трудоемкость таких вычислений может оцениваться как T'= n2/p операций.

После обмена данными между подзадачами на втором этапе вычислений

каждый процессор суммирует полученные значения для своего блока

результирующего вектора c. Количество суммируемых значений для каждого

элемента ci вектора c совпадает с числом процессоров p, размер блока вектора c

на одном процессоре равен n/p, и, тем самым, число выполняемых операций

для второго этапа оказывается равным T''=n. С учетом полученных

соотношений показатели ускорения и эффективности параллельного алгоритма

могут быть выражены следующим образом:

(6.10)

Теперь рассмотрим более точные соотношения для оценки времени

выполнения параллельного алгоритма. С учетом ранее проведенных

рассуждений время выполнения вычислительных операций алгоритма может

быть оценено при помощи выражения

(6.11)

(здесь, как и ранее, τ есть время выполнения одной элементарной скалярной

операции).

Для выполнения операции обобщенной передачи данных рассмотрим два

возможных способа реализации (см. также лекцию 3). Первый способ

обеспечивается алгоритмом, согласно которому каждый процессор

последовательно передает свои данные всем остальным процессорам

вычислительном системы. Предположим, что процессоры могут одновременно

отправлять и принимать сообщения и между любой парой процессоров имеется

прямая линия связи, тогда оценка трудоемкости (время исполнения) такого

алгоритма обобщенной передачи данных может быть определена как

(6.12)

(напомним, что – латентность сети передачи данных, β – пропускная

способность сети, w – размер элемента данных в байтах).

Второй способ выполнения операции обмена данными рассмотрен в лекции 3,

когда топология вычислительной сети может быть представлена в виде

гиперкуба. Как было показано, выполнение такого алгоритма может быть

осуществлено за шагов, на каждом из которых каждый процессор

Page 57: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

передает и получает сообщение из n/2 элементов. Как результат, время

операции передачи данных при таком подходе составляет величину:

(6.13)

С учетом (6.11) – (6.13) общее время выполнения параллельного алгоритма

умножения матрицы на вектор при разбиении данных по столбцам выражается

следующими соотношениями.

Для первого способа выполнения операции передачи данных

(6.14)

Для второго способа выполнения операции передачи данных

(6.15)

6.6.4. Результаты вычислительных экспериментов

Вычислительные эксперименты для оценки эффективности параллельного

алгоритма умножения матрицы на вектор при разбиении данных по столбцам

проводились при условиях, указанных в п. 6.5.5. Результаты вычислительных

экспериментов приведены в таблице 6.3.

Таблица 6.3. Результаты вычислительных экспериментов по исследованию

параллельного алгоритма умножения матрицы на вектор, основанного на разбиении

матрицы по столбцам

Размер

матрицы

Последовательный

алгоритм

Параллельный алгоритм

2 процессора 4 процессора 8 процессоров

Время Ускорение Время Ускорение Время Ускорение

1000 0,0041 0,0022 1,8352 0,0015 3,1538 0,0008 4,9409

2000 0,016 0,0085 1,8799 0,0046 3,4246 0,0029 5,4682

3000 0,031 0,019 1,6315 0,0095 3,2413 0,0055 5,5456

4000 0,062 0,0331 1,8679 0,0168 3,6714 0,0090 6,8599

5000 0,11 0,0518 2,1228 0,0265 4,1361 0,0136 8,0580

Сравнение экспериментального времени выполнения эксперимента и

времени Tp, вычисленного по соотношениям (6.14), (6.15), представлено в

Page 58: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

таблице 6.4 и на рис. 6.6 и 6.7. Теоретическое время вычисляется согласно

(6.14), а теоретическое время – в соответствии с (6.15).

Рис. 6.6. График зависимости теоретического и экспериментального времени

выполнения параллельного алгоритма на четырех процессорах от объема

исходных данных (ленточное разбиение матрицы по столбцам)

Таблица 6.4. Сравнение экспериментального и теоретического времени

выполнения параллельного алгоритма умножения матрицы на вектор,

основанного на разбиении матрицы по столбцам

Размер

матрицы

2 процессора 4 процессора 8 процессоров

1000 0,0022 0,0021 0,0021 0,0013 0,0013 0,0014 0,0008 0,0011 0,0015

2000 0,0085 0,0082 0,0080 0,0046 0,0044 0,0044 0,0029 0,0027 0,0031

3000 0,019 0,0177 0,0177 0,0095 0,0094 0,0094 0,0055 0,0054 0,0056

4000 0,0331 0,0313 0,0313 0,0168 0,0163 0,0162 0,0090 0,0090 0,0091

5000 0,0518 0,0487 0,0487 0,0265 0,0251 0,0251 0,0136 0,0135 0,0136

Page 59: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Рис. 6.7. Зависимость ускорения от количества процессоров при выполнении

параллельного алгоритма умножения матрицы на вектор (ленточное разбиение

матрицы по столбцам) для разных размеров матриц

6.7. Умножение матрицы на вектор при блочном разделении данных

Рассмотрим теперь параллельный алгоритм умножения матрицы на вектор,

который основан на ином способе разделения данных – на разбиении матрицы

на прямоугольные фрагменты (блоки).

6.7.1. Определение подзадач

Блочная схема разбиения матриц подробно рассмотрена в подразделе 6.1. При

таком способе разделения данных исходная матрица A представляется в виде

набора прямоугольных блоков:

где Aij, 0 i<s, 0 j<q, есть блок матрицы:

(здесь, как и ранее, предполагается, что p=s·q, количество строк матрицы

является кратным s, а количество столбцов – кратным q, то есть m=k·s и n=l·q).

При использовании блочного представления матрицы A базовые подзадачи

целесообразно определить на основе вычислений, выполняемых над

матричными блоками. Для нумерации подзадач могут применяться индексы

располагаемых в подзадачах блоков матрицы A, т.е. подзадача (i,j) содержит

блок Aij. Помимо блока матрицы A каждая подзадача должна содержать также

и блок вектора b. При этом для блоков одной и той же подзадачи должны

соблюдаться определенные правила соответствия – операция умножения блока

матрицы A ij может быть выполнена только, если блок вектора b'(i,j) имеет вид

6.7.2. Выделение информационных зависимостей

Рассмотрим общую схему параллельных вычислений для операции умножения

матрицы на вектор при блочном разделении исходных данных. После

перемножения блоков матрицы A и вектора b каждая подзадача (i,j) будет

Page 60: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

содержать вектор частичных результатов c'(i,j), определяемый в соответствии с

выражениями

Поэлементное суммирование векторов частичных результатов для каждой

горизонтальной полосы (данная процедура часто именуется операцией

редукции – см. лекцию 3) блоков матрицы A позволяет получить

результирующий вектор c

Для размещения вектора c применим ту же схему, что и для исходного вектора

b: организуем вычисления таким образом, чтобы при завершении расчетов

вектор c располагался поблочно в каждой из вертикальных полос блоков

матрицы A (тем самым, каждый блок вектора c должен быть продублирован по

каждой горизонтальной полосе). Выполнение всех необходимых действий для

этого – суммирование частичных результатов и дублирование блоков

результирующего вектора — может быть обеспечено при помощи функции

MPI_Allreduce библиотеки MPI.

Общая схема выполняемых вычислений для умножения матрицы на вектор при

блочном разделении :

Рис. 6.8. Общая схема параллельного алгоритма умножения матрицы на вектор

при блочном разделении данных: a) исходное распределение результатов, б)

распределение векторов частичных результатов, в) распределение блоков

результирующего вектора c

Page 61: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Рассмотрев представленную схему параллельных вычислений, можно сделать

вывод, что информационная зависимость базовых подзадач проявляется только

на этапе суммирования результатов перемножения блоков матрицы A и блоков

вектора b. Выполнение таких расчетов может быть выполнено по обычной

каскадной схеме (см. лекцию 3), и, как результат, характер имеющихся

информационных связей для подзадач одной и той же горизонтальной полосы

блоков соответствует структуре двоичного дерева.

6.7.3. Масштабирование и распределение подзадач по процессорам

Размер блоков матрицы А может быть подобран таким образом, чтобы общее

количество базовых подзадач совпадало с числом процессоров p. Так,

например, если определить размер блочной решетки как p=s·q, то

k=m/s, l=n/q,

где k и l есть количество строк и столбцов в блоках матрицы А. Такой способ

определения размера блоков приводит к тому, что объем вычислений в каждой

подзадаче является равным, и, тем самым, достигается полная балансировка

вычислительной нагрузки между процессорами.

Возможность выбора остается при определении размеров блочной структуры

матрицы А. Большое количество блоков по горизонтали приводит к

возрастанию числа итераций в операции редукции результатов блочного

умножения, а увеличение размера блочной решетки по вертикали повышает

объем передаваемых данных между процессорами. Простое, часто применяемое

решение состоит в использовании одинакового количества блоков по вертикали

и горизонтали, т.е.

Следует отметить, что блочная схема разделения данных является обобщением

всех рассмотренных в данной лекции подходов. Действительно, при q=1 блоки

сводятся к горизонтальным полосам матрицы А, при s=1 исходные данные

разбиваются на вертикальные полосы.

При решении вопроса распределения подзадач между процессорами должна

учитываться возможность эффективного выполнения операции редукции.

Возможный вариант подходящего способа распределения состоит в выделении

для подзадач одной и той же горизонтальной полосы блоков множества

процессоров, структура сети передачи данных между которыми имеет вид

гиперкуба или полного графа.

Page 62: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

7. Оценка эффективности параллельных

алгоритмов

Выполним анализ эффективности параллельного алгоритма умножения

матрицы на вектор при обычных уже предположениях, что матрица А является

квадратной, т.е. m=n. Будем предполагать также, что процессоры,

составляющие многопроцессорную вычислительную систему, образуют

прямоугольную решетку p=s×q (s – количество строк в процессорной решетке,

q – количество столбцов).

Общий анализ эффективности приводит к идеальным показателям

параллельного алгоритма:

(6.16)

Для уточнения полученных соотношений оценим более точно количество

вычислительных операций алгоритма и учтем затраты на выполнение операций

передачи данных между процессорами.

Общее время умножения блоков матрицы А и вектора b может быть

определено как

(6.17)

Операция редукции данных может быть выполнена с использованием

каскадной схемы и включает, тем самым, log2q итераций передачи сообщений

размера . Как результат, оценка коммуникационных затрат

параллельного алгоритма при использовании модели Хокни может быть

определена при помощи следующего выражения

(6.18)

Таким образом, общее время выполнения параллельного алгоритма умножения

матрицы на вектор при блочном разделении данных составляет

(6.19)

6.7.5. Результаты вычислительных экспериментов

Page 63: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Вычислительные эксперименты для оценки эффективности параллельного

алгоритма проводились при тех же условиях, что и ранее выполненные расчеты

(см. п. 6.5.5). Результаты экспериментов приведены в таблице 6.5. Вычисления

проводились с использованием четырех и девяти процессоров.

Сравнение экспериментального времени выполнения эксперимента и

теоретического времени T p, вычисленного в соответствии с выражением (6.19),

представлено в таблице 6.5 и на рис. 6.10.

Таблица 6.5. Результаты вычислительных экспериментов по исследованию

параллельного алгоритма умножения матрицы на вектор при блочном

разделении данных

Размер

матриц

Последовательный

алгоритм

Параллельный алгоритм

4 процессора 9 процессоров

Время Ускорение Время Ускорение

1000 0,0041 0,0028 1,4260 0,0011 3,7998

2000 0,016 0,0099 1,6127 0,0095 3,2614

3000 0,031 0,0214 1,4441 0,0095 3,2614

4000 0,062 0,0381 1,6254 0,0175 3,5420

5000 0,11 0,0583 1,8860 0,0263 4,1755

Рис. 6.9. Зависимость ускорения от количества процессоров при выполнении

параллельного алгоритма умножения матрицы на вектор (блочное разбиение

матрицы) для разных размеров матриц

Таблица 6.5. Сравнение экспериментального и теоретического времени

выполнения параллельного алгоритма умножения матрицы на вектор при

блочном разделении данных

Размер матриц Последовательный

алгоритм

Параллельный

алгоритм

Page 64: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1000 0,0025 0,0028 0,0012 0,0011

2000 0,0095 0,0099 0,0043 0,0042

3000 0,0212 0,0214 0,0095 0,0095

4000 0,0376 0,0381 0,0168 0,0175

5000 0,0586 0,0583 0,0262 0,0263

Рис. 6.10. График зависимости экспериментального и теоретического времени

проведения эксперимента на четырех процессорах от объема исходных данных

(блочное разбиение матрицы)

6.8. Краткий обзор лекции

В данной лекции на примере задачи умножения матрицы на вектор

рассматриваются возможные схемы разделения матриц между процессорами

многопроцессорной вычислительной системы, которые могут быть

использованы для организации параллельных вычислений при выполнении

матричных операций. В числе излагаемых схем способы разбиения матриц на

полосы (по вертикали или горизонтали) или на прямоугольные наборы

элементов (блоки).

Далее в лекции с использованием рассмотренных способов разделения матриц

подробно излагаются три возможных варианта параллельного выполнения

операции умножения матрицы на вектор. Первый алгоритм основан на

разделении матрицы между процессорами по строкам, второй – на разделении

матрицы по столбцам, а третий – на блочном разделении данных. Каждый

алгоритм представлен в соответствии с общей схемой, описанной в лекции 4,

— вначале определяются базовые подзадачи, затем выделяются

информационные зависимости подзадач, далее обсуждается масштабирование и

распределение подзадач между процессорами. В завершение для каждого

алгоритма проводится анализ эффективности получаемых параллельных

Page 65: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

вычислений и приводятся результаты вычислительных экспериментов. Для

алгоритма умножения матрицы на вектор при ленточном разделении данных по

строкам приводится возможный вариант программной реализации.

Полученные показатели эффективности показывают, что все используемые

способы разделения данных приводят к равномерной балансировке

вычислительной нагрузки, и отличия имеются только в трудоемкости

выполняемых информационных взаимодействий между процессорами. В этом

отношении представляется интересным проследить, как выбор способа

разделения данных влияет на характер необходимых операций передачи

данных, и выделить основные различия в коммуникационных действиях разных

алгоритмов. Кроме того, важным является определение целесообразной

структуры линий связи между процессорами для эффективного выполнения

соответствующего параллельного алгоритма. Так, например, алгоритмы,

основанные на ленточном разделении данных, ориентированы на топологию

сети в виде гиперкуба или полного графа. Для реализации алгоритма,

основанного на блочном разделении данных, необходимо наличие топологии

решетки.

На рис. 6.11 на общем графике представлены показатели ускорения,

полученные в результате выполнения вычислительных экспериментов для всех

рассмотренных алгоритмов. Следует отметить, что дополнительные расчеты

показывают , что при большем количестве процессоров и при большом размере

матриц более эффективным становится блочный алгоритм умножения.

Рис. 6.11. Показатели ускорения рассмотренных параллельных алгоритмов

умножения по результатам вычислительных экспериментов с матрицами

размера 2000x2000 и векторами из 2000 элементов

Page 66: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

8. Сложностные классы задач Рассматривая некоторую алгоритмически разрешимую задачу, и

анализируя один из алгоритмов ее решения, мы можем получить оценку

трудоемкости этого алгоритма в худшем случае – ˆA(DA)=O(g(DA)). Такие же

оценки мы можем получить и для других известных алгоритмов решения

данной задачи. Рассматривая задачу с этой точки зрения, возникает резонный

вопрос – а существует ли функциональный нижний предел для g(DA) и если

«да», то существует ли алгоритм, решающий задачу с такой трудоемкостью в

худшем случае.

Другая, более точная формулировка, имеет следующий вид: какова

оценка сложности самого «быстрого» алгоритма решения данной задачи в

худшем случае? Очевидно, что это оценка самой задачи, а не какого либо

алгоритма ее решения. Таким образом, мы приходим к определению понятия

функционального теоретического нижнего предела трудоемкости задачи в

худшем случае:

Fthlim= min (Fa^ (D))

Если мы можем на основе теоретических рассуждений доказать

существование и получить оценивающую функцию, то мы можем утверждать,

что любой алгоритм, решающий данную задачу работает не быстрее, чем с

оценкой Fthlim в худшем случае:

Fa^ (D) = (Fthlim)

Приведем ряд примеров:

1) Задача поиска максимума в массиве A=(a1,…,an) – для этой задачи,

очевидно должны быть просмотрены все элементы, и Fthlim= (n).

2) Задача умножения матриц - для этой задачи можно сделать

предположение, что необходимо выполнить некоторые арифметические

операции со всеми исходными данными, теоретическое обоснование какой–

либо другой оценки на сегодня не известно [6], что приводит нас к оценке

Fthlim= (n2). Отметим, что лучший алгоритм умножения матриц имеет оценку

(n2,34

) [6]. Расхождение между теоретическим пределом и оценкой лучшего

известного алгоритма позволяет предположить, что либо существует, но еще не

найден более быстрый алгоритм умножения матриц, либо оценка (n2,34

)

должна быть доказана, как теоретический предел.

В начале 1960-х годов, в связи с началом широкого использования

вычислительной техники для решения практических задач, возник вопрос о

границах практической применимости данного алгоритма решения задачи в

смысле ограничений на ее размерность. Какие задачи могут быть решены на

ЭВМ за реальное время?

Ответ на этот вопрос был дан в работах Кобмена (Alan Cobham, 1964), и

Эдмондса (Jack Edmonds, 1965), где были введены сложностные классы задач.

Page 67: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

1) Класс P (задачи с полиномиальной сложностью)

Задача называется полиномиальной, т.е. относится к классу P, если

существует константа k и алгоритм, решающий задачу с Fa(n)=O(nk), где n -

длина входа алгоритма в битах n = |D| [6].

Задачи класса P – это интуитивно, задачи, решаемые за реальное время.

Отметим следующие преимущества алгоритмов из этого класса:

для большинства задач из класса P константа k меньше 6;

класс P инвариантен по модели вычислений (для широкого класса

моделей);

класс P обладает свойством естественной замкнутости (сумма или

произведение полиномов есть полином).

Таким образом, задачи класса P есть уточнение определения

«практически разрешимой» задачи.

2) Класс NP (полиномиально проверяемые задачи)

Представим себе, что некоторый алгоритм получает решение некоторой

задачи – соответствует ли полученный ответ поставленной задаче, и насколько

быстро мы можем проверить его правильность?

Рассмотрим, например задачу о сумме:

Давно N чисел – А = (a1,…an) и число V.

Задача: Найти вектор (массив) X=(x1,…,xn), xi0,1, такой, что aixi = V.

Содержательно: может ли быть представлено число V в виде суммы каких

либо элементов массива А.

Если какой-то алгоритм выдает результат – массив X, то проверка

правильности этого результата может быть выполнена с полиномиальной

сложностью: проверка aixi = V требует не более (N) операций.

Формально: DDA, |D|=n поставим в соответствие сертификат SSA,

такой что |S|=O (nl) и алгоритм As = As (D,S), такой, что он выдает «1», если

решение правильно, и «0», если решение неверно. Тогда задача принадлежит

классу NP, если F (As)=O (nm) [6].

Содержательно задача относится к классу NP, если ее решение

некоторым алгоритмом может быть быстро (полиномиально) проверено.

Проблема P = NP

После введения в теорию алгоритмов понятий сложностных классов

Эдмондсом (Edmonds, 1965) была поставлена основная проблема теории

сложности – P = NP ? Словесная формулировка проблемы имеет вид: можно ли

все задачи, решение которых проверяется с полиномиальной сложностью,

решить за полиномиальное время ? [6]

Page 68: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Очевидно, что любая задача, принадлежащая классу P, принадлежит и

классу NP, т.к. она может быть полиномиально проверена – задача проверки

решения может состоять просто в повторном решении задачи.

На сегодня отсутствуют теоретические доказательства как совпадения

этих классов (P=NP), так и их несовпадения. Предположение состоит в том, что

класс P является собственным подмножеством класса NP, т.е. NP \ P не пусто –

рис 1

Рис 1 Соотношение классов P и NP

Класс NPC (NP – полные задачи)

Понятие NP – полноты было введено независимо Куком (Stephen Cook,

1971) и Левиным (журнал «Проблемы передачи информации», 1973,т.9, вып. 3)

и основывается на понятии сводимости одной задачи к другой [6].

Сводимость может быть представлена следующим образом: если мы

имеем задачу 1 и решающий эту задачу алгоритм, выдающий правильный ответ

для всех конкретных проблем, составляющих задачу, а для задачи 2 алгоритм

решения неизвестен, то если мы можем переформулировать (свести) задачу 2 в

терминах задачи 1, то мы решаем задачу 2.

Таким образом, если задача 1 задана множеством конкретных проблем

DA1, а задача 2 – множеством, и существует функция fs (алгоритм), сводящая

конкретную постановку задачи 2 (dА2) к конкретной постановке задачи 1(dА1):

fs(d(2)DA2) = d(1)DA1, то задача 2 сводима к задаче 1.

Если при этом FA (fs) = O(nk), т.е. алгоритм сведения принадлежит классу

P, то говорят, что задача 1 полиномиально сводится к задаче 2 [6].

Принято говорить, что задача задается некоторым языком, тогда если

задача 1 задана языком L1, а задача 2 – языком L2, то полиномиальная

сводимость обозначается следующим образом: L2 p L1.

Определение класса NPC (NP-complete) или класса NP-полных задач

требует выполнения следующих двух условий: во-первых, задача должна

принадлежать классу NP (L NP), и, во-вторых, к ней полиномиально должны

сводиться все задачи из класса NP (Lx P L, для каждого Lx NP), что

схематично представлено на рис 2.

P

NP

NP \ P0

Page 69: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Рис 2 Сводимость и класс и NPC

Для класса NPC доказана следующая теорема: Если существует задача,

принадлежащая классу NPC, для которой существует полиномиальный

алгоритм решения (F = O(nk)), то класс P совпадает с классом NP, т.е. P=NP [6].

Схема доказательства состоит в сведении любой задачи из NP к данной

задаче из класса NPC с полиномиальной трудоемкостью и решении этой задачи

за полиномиальное время (по условию теоремы).

В настоящее время доказано существование сотен NP– полных задач

[6,7], но ни для одной из них пока не удалось найти полиномиального

алгоритма решения. В настоящее время исследователи предполагают

следующее соотношение классов, показанное на рис 3 – P NP, то есть NP \ P

, и задачи из класса NPC не могут быть решены (сегодня) с полиномиальной

трудоемкостью.

Рис 3 Соотношение классов P, NP, NPC

Примеры NP – полных задач

Задача о выполнимости схемы

Рассмотрим схему из функциональных элементов «и», «или», «не» с n

битовыми входами и одним выходом, состоящую не более, чем из O(nk)

элементов – рис 4

Рис 4 Абстрактная функциональная схема

NP NPC

NP

P

NPC

n O(n

k)

Page 70: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

Будем понимать под выполняющим набором значений из множества 0,1

на входе схемы, такой набор входов – значения x1,…,xn, при котором на выходе

схемы будет значение «1».

Формулировка задачи – существует ли для данной схемы выполняющий

набор значений входа. Очевидно, что задача принадлежит классу NP – проверка

предъявленного выполняющего набора не сложнее количества

функциональных элементов, и следовательно не больше чем O(nk).

Это была одна из первых задач, для которой была доказана ее NP

полнота, т.е. любая задача из класса NP полиномиально сводима к задаче о

выполнимости схемы [6].

Решение этой задачи может быть получено перебором всех 2n возможных

значений входа с последующей проверкой на соответствие условию

выполняющего набора. В худшем случае придется проверить все возможные

значения входа, что приводит к оценке F^(n) = O(n

k * 2

n). Для этой, как и для

всех других NP–полных задач не известен полиномиальный алгоритм решения.

2 Задача о сумме

Уже рассмотренная задача о сумме также является NP–полной, отметим,

что если количество слагаемых фиксировано, то сложность задачи является

полиномиальной, так как:

для 2-х слагаемых СN2=(N*(N-1))/(1*2) = O(N

2);

для 3-х слагаемых CN3=(N*(N-1)*(N-2))/(1*2*3) = O(N

3).

Однако в общем случае придется перебирать 2N различных вариантов, так

как по биномиальной теореме (a+b)N

= cNk * a

N-k * b

k, а при a=b=1, имеем:

(1+1)N

= CNk = 2

N, следовательно, FA (N, V) = O(N * 2

N).

3 Задача о клике

Пусть дан граф G = G(V,E), где V – множество из n вершин, а E –

множество ребер. Будем понимать под кликой максимальный по количеству

вершин полный подграф в графе в G.

Задача состоит в определении клики в заданном графе G

Поскольку в полном графе на m вершинах имеется m(m-1)/2 ребер, то

проверка, является ли данный граф полным, имеет сложность O(m2). Очевидно,

что если мы рассматриваем подграф с m вершинами в графе G с вершинами (m

< n), то всего существует Cnm различных подграфов. Если в задаче о клике

количество вершин клики фиксировано, то перебирающий алгоритм имеет

полиномиальную сложность:

F(m, n) = O(m2 * Cn

m) = O(m

2 * n

m).

Однако в общем случае придется проверять все подграфы с количеством

вершин m = (2, n) на их полноту и определить максимальное значения m для

Page 71: 1. Алгоритмы и способы их описанияhpc-education.ru/files/lectures/2011/lymar/lymar_2011_lectures.pdf · 1. Алгоритмы и способы их описания

которого в данном графе G существует полный подграф, что приводит к оценке

в худшем случае:

F^(n) = O( k

2 * Cn

k) O (n

2 * 2

n)

k