SlideShare a Scribd company logo
1 of 144
Download to read offline
1
Министерство образования и науки Российской Федерации
Федеральное агентство по образованию
Ярославский государственный университет им. П. Г. Демидова
С.Г. Волченков, Ю.В. Богомолов
Методы построения
эффективных алгоритмов
Учебное пособие
Рекомендовано
Научно-методическим советом университета
для студентов специальности Математическое обеспечение
и администрирование информационных систем
Ярославль 2005
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
2
УДК 510.5
ББК В127я73
В 68
Рекомендовано
Редакционно-издательским советом университета
в качестве учебного издания. План 2005 года
Рецензенты:
кандидат педагогических наук Н.Л. Дашниц;
кафедра теории и методики обучения информатике
Ярославского государственного педагогического университета
им. К.Д. Ушинского
В 68
Волченков, С.Г., Богомолов, Ю.В. Методы построения эф-
фективных алгоритмов : учебное пособие / С.Г. Волченков,
Ю.В. Богомолов ; Яросл. гос. ун-т. – Ярославль : ЯрГУ, 2005. –
146 с.
ISBN 5-8397-0401-6
Учебное пособие (продолжение одноименного учебного по-
собия, изданного в 2004 г.) посвящено различным аспектам по-
строения и анализа эффективных алгоритмов решения некото-
рых задач. Материал разбит на главы по предметным областям и
по методам решения задач. Главы посвящены геометрическим
методам в задачах информатики, рекурсии, динамическому про-
граммированию и структурам данных.
Пособие рассчитано на студентов факультетов информатики
и вычислительной техники, обучающихся по специальности
351500 Математическое обеспечение и администрирование ин-
формационных систем (дисциплина "Методы построения эффек-
тивных алгоритмов", блок ДС), очной формы обучения, а также
может оказаться интересным для школьников, принимающих
участие в олимпиадах по информатике.
УДК 510.5
ББК В127я73
ISBN 5-8397-0401-6 © Ярославский государственный университет, 2005
© С.Г. Волченков, Ю.В. Богомолов, 2005
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
3
Предисловие
Данное пособие не претендует на описание всех суще-
ствующих методов построения эффективных алгоритмов.
Достаточно сказать, что учебник по алгоритмам, недавно
выпущенный в Массачусетском технологическом институте
[1] и переведенный на русский язык, содержит 955 страниц!
И этот учебник, в свою очередь, тоже далеко не полон. Счи-
тается, что относительной полнотой обладает трёхтомник
Д. Кнута [2], правда, в нём очень сильно ограничен круг
рассматриваемых вопросов, но те, что рассматриваются, ра-
зобраны чрезвычайно пунктуально и интересно. Также су-
ществуют учебники и монографии, которые, как правило,
либо узкоспециализированны, либо, напротив, пытаясь ох-
ватить возможно более широкий круг алгоритмов, носят по-
верхностный характер и не содержат достаточного круга за-
дач [3 – 7, 9 – 13]. Создалась парадоксальная ситуация, ко-
гда при относительно широком освещении рассматривае-
мой тематики литература, которую можно было бы реко-
мендовать для изучения в рамках соответствующего учеб-
ного курса, труднодоступна.
Предлагаемое учебное пособие является продолжением
пособия, изданного в 2004 году. В нем рассмотрены методы
построения алгоритмов на графах, алгоритмов сортировки и
поиска, а также рассматриваются вопросы переключения
алгоритмов.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
4
Глава 1
Алгоритмы на графах
Введение
В одной из компьютерных игр как-то встретилась такая голо-
воломка. На неровной шахматной доске, состоящей из 10 клеток
(рис.1), расположены два белых и два черных коня. Требуется
поменять коней местами, т.е. расположить белых на места чер-
ных и наоборот. Коней разрешается переставлять по правилам
шахматной игры, т.е. передвигать "буквой Г" на любую свобод-
ную клетку. За один ход можно передвинуть одного коня.
Рис. 1
Несколько попыток решить задачу сходу ни к чему не приве-
ли. Вооружившись карандашом и бумагой, я попытался фиксиро-
вать промежуточные положения коней, но скоро убедился, что
записей стало катастрофически много. Вздохнув и призвав на
помощь знания ранее встречавшихся головоломок и задач, я стал
строить математическую модель задачи. Во-первых, я обозначил
клетки доски числами от 1 до 10 и соединил отрезками центры
клеток, которые связаны друг с другом ходом коня. Получился
рисунок, содержащий всевозможные траектории передвижения
коней по доске (рис. 2)
•
• • • •
• • •
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
5
• •0
Рис. 2
Теперь можно было заметить, что траектории движения ко-
ней довольно сильно запутаны, и в них трудно разобраться. Рас-
путать их было несложно, разместив числа, соответствующие
клеткам, в другом порядке: так чтобы клетки, соединенные друг с
другом, были размещены рядом. Получился рисунок 3.
Рис. 3
Теперь на получившейся схеме отметим коней: белых – кру-
жочками, черных – квадратиками (рис. 4).
Рис. 4
Остается вспомнить, что нам надо сделать. Надо поменять
местами "встретившихся на одной тропинке коней". Для маневра
оставлена клетка 6, на которую может встать один из коней, что-
бы пропустить мимо себя других. Теперь решение задачи рожда-
ется несложно.
Белого коня с клетки 4 передвигаем на клетку 6, пропускаем
черных коней с их начальных позиций на клетки 7 и 1. Затем бе-
лого коня с клетки 6 перегоняем на клетку 3. Один конь на месте!
Отгоняем черных коней на клетки 10 и 2, чтобы освободить
для белого коня, стоящего на клетке 5, проход к клетке 6. Когда
тот туда проходит, черный конь с клетки 10 беспрепятственно
продвигается на клетку 5. Второй конь на месте!
Теперь второй черный конь с клетки 2 проходит мимо клетки
6 на клетку 1, освобождая проход для белого коня. Тот немедлен-
но пользуется этой ситуацией и продвигается на свое место с
клетки 6 на клетку 2.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
6
Последний черный конь становится на требуемую позицию с
поля 1 на 4. Кавалерийский маневр завершен!
А теперь приведем полный список ходов коней, с помощью
которых удалось решить задачу.
1. 4 – 6
2. 2 – 10
3. 10 – 4
4. 4 –1
5. 1 – 7
6. 3 – 9
7. 9 – 8
8. 8 – 2
9. 2 – 10
10. 10 – 4
11. 4 – 1
12. 6 – 4
13. 4 – 10
14. 10 – 2
15. 2 – 8
16. 8 – 9
17. 9 – 3
18. 1 – 4
19. 4 – 10
20. 10 – 2
21. 7 –1
22. 1 – 4
23. 4 –10
24. 5 – 7
25. 7 – 1
26. 1 – 4
27. 4 – 6
28. 10 – 4
29. 4 – 1
30. 1 – 7
31. 7 – 5
32. 2 –10
33. 10 – 4
34. 4 – 1
35. 6 – 4
36. 4 – 10
37. 10 – 2
38. 1 – 4
Более подробный анализ показывает, что полученный алго-
ритм, содержащий 38 ходов, является кратчайшим из всех воз-
можных!
Определения и примеры
Итак, в предыдущей части, чтобы успешно решить задачу,
нам потребовалось представить её условие наглядно. Для этого
мы воспользовались рисунком, на котором отметили возможные
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
7
переходы коней с одной позиции на другую. Подобные рисунки
принято называть графами.
Наглядное представление о графе можно получить, если
представить себе некоторое множество точек плоскости X, назы-
ваемых вершинами, и множество отрезков U, соединяющих все
или некоторые из вершин. Если при этом рассматриваемые от-
резки являются направленными, то они называются дугами, а ес-
ли ненаправленными, то ребрами. Дуги используются для обо-
значения несимметричных отношений между вершинами, напри-
мер отношение "отец – сын", или возможных переходов от одной
вершины к другой, например если вершины изображают шахмат-
ные позиции, то иногда из одной в другую можно перейти, а на-
оборот нельзя (ход пешкой или рокировка). Ребра же изображают
симметричные отношения между вершинами, например, если
вершины – люди, то наличие ребра между вершинами может оз-
начать, что люди знакомы друг с другом. Принято при изображе-
нии графов на дугах рисовать стрелку, идущую из начальной
вершины в конечную.
Итак, что же такое граф? Постараемся дать более формальное
определение графа и его компонентов, а также привести приме-
ры.
Математически граф G можно определить как пару множеств
Х и U: G = (Х,U), где X – конечное множество, называемое мно-
жеством вершин, а U – некоторое множество пар вершин их X.
На рис. 5 изображен граф, вершинами которого являются
точки а, b, с, d, е, g, h, а дугами – отрезки (а, а), (с, b), (с, d), (с, е),
(d, с), (d, d), (е, d), (g, h). Примерами графов являются отношения
отцовства и материнства на множестве людей, карта дорог на ме-
стности, схема соединений электрических приборов, отношения
превосходства одних участников турнира над другими, и т.п.
Введем некоторые понятия и определения, служащие для
описания частей графов и их различных видов.
Подграфом GA графа G = (X, Г) называется граф, в который
входит лишь часть вершин графа G, образующих множество А,
вместе с некоторыми дугами, соединяющими эти вершины, на-
пример очерченная пунктиром область на рис. 5.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
8
Рис. 5. Граф и подграф
Другими важными понятиями являются понятия пути и кон-
тура. Ранее было дано определение дуги как направленного от-
резка, соединяющего две вершины. Дуга, соединяющая вершины
а и b и направленная от а к b, обозначается u = (а, b).
Путем в графе G называют такую последовательность дуг
m = (Ui, ...,Uk), в которой конец каждой предыдущей дуги совпа-
дает с началом следующей. Путь m, последовательными верши-
нами которого являются вершины а, b, ..., m, обозначается через
m = (a, b, ..., m).
Длиной пути m = (u1, ..., ur) называют число l(m) = k, равное
числу дуг, составляющих путь m. Иногда каждой дуге Ui припи-
сывают некоторое число l(ui), называемое длиной дуги. Тогда
длина пути определяется как сумма длин дуг, составляющих путь
Путь, в котором никакая дуга не встречается дважды, назы-
вается простым. Путь, в котором никакая вершина не встречает-
ся дважды, называется элементарным.
Контур - это конечный путь m = (Xi,...,Xk), у которого на-
чальная вершина Xi совпадает с конечной Xk. При этом контур на-
зывается элементарным, если все его вершины различны (за ис-
ключением начальной и конечной, которые совпадают). Контур
единичной длины, образованный дугой вида (а, а), называется
петлей. Так, на рис. 5 (е, d, с, b) – путь, (с, е, d, с) – контур, (d, d) -
петля.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
9
Рис. 6. Неориентированный граф
Иногда граф рассматривают без учета ориентации дуг, тогда
его называют неориентированным графом. Для неориентирован-
ного графа понятие "дуга", "путь" и "контур" заменяются поня-
тиями "ребро", "цепь", "цикл". Ребро - это отрезок, соединяющий
две вершины. Цепь - последовательность ребер. Цикл - цепь, у
которой начальная и конечная вершины совпадают.
На рис. 6 приведен пример неориентированного графа, у ко-
торого вершины обозначены цифрами, а ребра - буквами латин-
ского алфавита.
Приведем еще несколько определений, служащих для ха-
рактеристики неориентированных графов.
Степенью вершины, х, обозначаемой deg(x) или dx, называ-
ют число ребер, инцидентных вершине х. Так, для графа на рис. 3
имеем: deg(b) = 2, deg(c) = 2, deg(a) = 3, deg(e) = 0. Если deg(x) = 1,
то вершину х называют висячей (вершина 4), если deg(x) = 0, то
вершину называют изолированной (вершина 5).
Нетрудно заметить, что сумма степеней всех вершин гра-
фа – четное число.
Доказательство следует из того, что каждое ребро добавляет
единицу к степени каждой из двух вершин, которые оно соединя-
ет, т. е. добавляет 2 к сумме степеней уже имеющихся вершин.
Следствие. В каждом графе число вершин нечетной степени
четно.
Для неориентированного графа понятия "подграф" и "час-
тичный граф" аналогичны соответствующим понятиям для ори-
ентированного графа.
С понятием неориентированного графа связана важная ха-
рактеристика, называемая связностью графа. Говорят, что граф
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
10
связен, если любые две его вершины можно соединить цепью.
Если граф G не связен, то его можно разбить на такие подграфы
Gi, что все вершины в каждом подграфе связны, а вершины из
различных подграфов не связны. Такие подграфы G, называют
компонентами связности графа G.
Если из графа на рис. 6 исключить изолированную вершину
5, то полученный граф будет связным. Граф на рис. 7 не связен и
имеет две компоненты связности, его можно превратить в связ-
ный, добавив ребро (мост), соединяющее вершины 3 и 5 (штри-
ховая линия). Удаление моста превращает связный граф в не-
связный.
Рис. 7. Мост в графе
Для того чтобы определить связность ориентированного
графа, не нужно обращать внимание на ориентацию дуг. Граф,
изображенный на рис. 5, несвязный. Однако его подграф, со-
стоящий из вершин a, с, d, е, является связным. Для ориентиро-
ванного графа существует понятие сильной связности. Граф
сильно связен, если для любых двух вершин (х и у) существует
путь, идущий из х в у.
Представления графов в компьютере
Описать неориентированный граф G можно путем задания
пары множеств (X, U), где Х – множество вершин; U – множество
ребер. Однако более удобным, особенно в случае представления
графа в компьютере, является описание неориентированного
графа с помощью матрицы смежности или инциденции, которые
строятся аналогично соответствующим матрицам для ориентиро-
ванных графов с той разницей, что не делается различия между
заходящей в вершину и исходящей из нее дугами. При этом вер-
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
11
шины x и у называют смежными, если существует соединяющее
их ребро, а само это ребро называется инцидентным вершинам х
и у. Для графа рис. 6 матрицы смежности и инциденции имеют
вид:
Матрица смежности:
Вершины
Вершины
1 2 3 4 5
1 0 1 1 1 0
2 1 0 1 0 0
3 1 1 0 0 0
4 1 0 0 0 0
5 0 0 0 0 0
Матрица инциденции:
Ребра
Вершины
1 2 3 4 5
a 1 1 0 0 0
b 0 1 1 0 0
c 1 0 1 0 0
d 1 0 0 1 0
Использование матриц смежности или инцидентности удоб-
но далеко не всегда. Представим, например, граф железных дорог
России, где вершинами являются отдельные станции, а ребрами –
участки дороги, соединяющие соответствующие эти станции. Яс-
но, что в таком графе много тысяч вершин, а значит, в матрице
смежности – несколько миллионов элементов. Причем, в каждой
строке этой матрицы количество элементов почти всегда равно
двум (через станцию почти вседа проходит только один путь, т.е.
она соединена только с двумя соседними станциями). Таким об-
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
12
разом, почти все элементы матрицы смежности равны нулю, и
значит, матрица содержит крайне мало информации. При этом
она занимает много места, и работать с ней неудобно.
Гораздо экономнее представлять дуги в виде списка, но при
этом появляется еще одна неприятность – очень трудно становит-
ся определить, какие дуги выходят из данной вершины, а такая
информация в графе, как правило, является главной.
Чтобы сохранить возможность быстрого определения множе-
ства дуг, исходящих из данной вершины, можно поступать сле-
дующим образом. Рассмотрим сначала работу с ориентирован-
ными графами, а затем распространим результат и на неориенти-
рованные графы.
Во-первых, список дуг отсортируем по первой вершине. Сна-
чала в таком отсортированном списке будут следовать дуги, ис-
ходящие из первой вершины, затем – из второй, и т.д. Искать
нужные дуги, конечно, станет легче, но можно пойти и дальше.
Заведем вспомогательный массив, состоящий из n элементов, в
котором i-ый элемент означает, с какого места в списке дуг начи-
наются дуги, выходящие их i-ой вершины. Назовем новый массив
справочным.
Таким образом, список дуг и соответствующий справочный
массив для графа, изображенного на рис. 6, будут выглядеть сле-
дующим образом:
Список дуг:
1. (1, 2)
2. (1, 3)
3. (1, 4)
4. (2, 1)
5. (2, 3)
6. (3, 1)
7. (3, 2)
8. (4, 1)
Справочный массив:
1. 1
2. 4
3. 6
4. 8
Заметим, что при таком представлении становится ненужным
хранить в списке дуг информацию о первой вершине!
Поэтому список дуг с оглавлением может выглядеть сле-
дующим образом:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
13
Список дуг:
1. 2
2. 3
3. 4
4. 1
5. 3
6. 1
7. 2
8. 1
Справочный массив:
1. 1
2. 4
3. 6
4. 8
Ориентированные графы представляются в виде матриц
смежности и инциденции аналогичным образом. Отличие в том,
что требуется разным образом отмечать начало и конец дуги. К
примеру, если из i-й вершины в j-ю идет дуга, то на пересечении
i-й строки и j-го столбца матрицы смежности будет стоять 1, но
это не означает, что в симметричной относительно главной диа-
гонали (на пересечении j-й строки и i-го столбца) ячейке матрицы
смежности тоже будет стоять единица (никто не гарантирует, что
из j-й вершины в i-ю тоже идет дуга). К примеру, для следующего
графа
матрица смежности будет выглядеть так:
Вершины
Вершины
1 2 3 4
1 0 1 0 1
2 1 0 0 0
3 0 1 0 1
4 0 0 0 0
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
14
Матрица инцидентности строится по уже знакомой схеме –
перечисляются дуги и отмечается, какие вершины какими дугами
связаны. Если дуга f идет от i-й вершины к j-й, то в соответст-
вующей данной дуге строке в i-м столбце поставим –1, а в j-м
столбце поставим 1. В незаполненные ячейки вписываются нули.
Для рассмотренного выше ориентированного графа матрица ин-
цидентности имеет следующий вид:
Ребра
Вершины
1 2 3 4
a –1 1 0 0
b 1 –1 0 0
c 0 1 –1 0
d –1 0 0 1
e 0 0 –1 1
Аналогично строится список дуг (вместо списка ребер), а
также список дуг с оглавлением. При этом необходимо помнить,
то дуги имеют направление, и наличие в списке, к примеру, дуги
(2, 5) не влечет наличия дуги (5, 2). В оглавлении приводятся ука-
затели на позицию в списке дуг, начиная с которой перечисляют-
ся дуги, исходящие из конкретных вершин.
Алгоритмы нахождения путей в графе
Чаще всего при работе с графами требуется находить в них
различные пути. Если граф представляет схему дорог, то эта за-
дача совершенно естественна. Но даже граф не является схемой
дорог, то и тогда пути могут иметь важное значение. В качестве
примера можно привести граф состояний шахматной партии, в
котором путь может означать способ достижения выигрыша.
Существуют разные алгоритмы отыскания путей в графе. Эти
алгоритмы ориентированы на конкретные задачи. Например, если
требуется просто установить наличие или отсутствие путей меж-
ду вершинами (связность графа), достаточно использовать волно-
вой алгоритм. Если же требуется искать путь с какими-то свойст-
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
15
вами, например самый короткий, то чаще используют алгоритмы
Дейкстры или Флойда.
Поиск в графе
Одной из наиболее важных задач на графах является задача
поиска. В вершинах графа можно хранить некоторые значения,
среди которых можно осуществлять поиск удовлетворяющих ус-
ловию элементов. Также иногда необходимо решать задачу обхо-
да графа, то есть перечисления всех его вершин (или значений,
записанных в этих вершинах) ровно по одному разу. Мы рас-
смотрим два способа обхода (поиска) вершин в графе – поиск в
глубину и поиск в ширину.
Поиск в глубину
Поиск (обход) начинаем с некоторой вершины. Сначала про-
сматриваем первую вершину (под просмотром можно понимать
вывод номера вершины на экран или в файл, анализ содержаще-
гося в вершине значения или какое-либо другое действие) – пусть
это вершина u. Потом просматриваем смежную с ней вершину
(v). Далее посматриваем вершину, смежную с v (вершина w), и
т. д. На каждом шаге после рассмотрения очередной вершины (t)
просматриваем произвольную из не просмотренных ранее вер-
шин, смежных с текущей вершиной t. Если же у вершины t нет
смежных вершин, которые мы еще не рассматривали, то возвра-
щаемся на предыдущую вершину и ищем непросмотренные
смежные (уже с ней) вершины. Если и у этой вершины нет "сосе-
дей", не просмотренных ранее, то возвращаемся еще на один шаг
назад, и т. д. Процесс заканчиваем тогда, когда на одном из шагов
алгоритма требуется сделать шаг назад относительно вершины, с
которой мы начинали просмотр.
При организации такого просмотра можно использовать стек
(для хранения номеров просматриваемых вершин) и массив (для
пометок просмотренных вершин). Считаем, что уже определены
операции помещения элемента в стек, выборки элемента с вер-
шины стека, просмотра элемента на вершине стека, проверки, яв-
ляется ли стек пустым. В массив M будем записывать 1 в k-ю
ячейку, если k-я вершина просмотрена, и 0 – в противном случае.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
16
В начале работы стек пуст, а массив M заполнен нулями. Пусть
C – матрица смежности графа (C[i,j] = 1, если есть ребро (i,j) и 0 –
в противном случае). Обход графа начнем с вершины с номером
1. Алгоритм опишем следующим образом:
Push(1); {поместили в стек номер
1-й вершины,...}
Просмотреть(1); {посмотрели ее...}
M[1]:=1; {и пометили как просмотренную}
while not Empty do {пока есть вершины,
подлежащие обработке...}
begin
v:=Top; {номер текущей вершины
берем с вершины стека}
s:=0; {будем записывать в s
номер очередной вершины}
for k:=1 to N do
if M[k]=0 and C[v,k]=1 {нашли
непросмотренную вершину,}
then begin {смежную с v}
s:=k; {запоминаем ее номер}
break; {выходим из цикла}
end;
if s<>0 then {если очередная вершина
была найдена,...}
begin
Просмотреть(s); {просматриваем ее}
M[s]:=1; {помечаем ее как просмотренную}
Push(s); {и помещаем ее в стек}
end
else
s:=Pop; {удаляем текущую вершину из стека}
end;
Алгоритм поиска в глубину можно записать и в рекурсивной
форме. В этом случае определим рекурсивную процедуру
Search(k), где k – номер вершины, начиная с которой мы осуще-
ствляем поиск в глубину:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
17
procedure Search(k: integer);
begin
Просмотреть(k);
M[k]:=1;
for t:=1 to N do
if (C[k,t]=1) and (M[t]=0) then Search(t);
end;
Таким образом, при данном способе поиска граф просматри-
ваем в глубину так, как это возможно, а когда дальнейший про-
смотр невозможен, возвращаемся немного назад и пытаемся про-
должить просмотр уже по несколько другому пути.
Поиск в ширину
Если при поиске в глубину мы последовательно просматри-
вали вершины графа до тех пор, пока это возможно, то при поис-
ке в ширину вначале будут просмотрены вершины, смежные с
начальной, потом – вершины, смежные с теми, которые смежны с
начальной, и т. д., пока не будут просмотрены все вершины гра-
фа. Иначе говоря, раньше будут просмотрены те вершины, кото-
рые находятся на меньшем расстоянии от начальной вершины
(под расстоянием между вершинами понимается длина кратчай-
шего пути между ними).
Подлежащие рассмотрению вершины удобно хранить в оче-
реди. В начале работы в очередь поместим номер начальной вер-
шины. Затем в очередь добавляем номера вершин, смежных с на-
чальной, а номер самой начальной вершины из очереди удалим.
Потом берем из очереди номер следующей вершины, помещаем в
очередь номера смежных с ней вершин, а саму вершину удаляем,
и т. д. Понятно, что при таком способе просмотра вершины, ко-
торые расположены ближе к начальной, будут рассмотрены
раньше, чем те, которые находятся от начальной вершины на
большем расстоянии (действительно, ведь они раньше помещены
в очередь просмотра вершин).
Ниже приведем алгоритм (при этом предполагаем, что опре-
делены операции работы с очередью – добавления элемента (In-
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
18
sert), удаления элемента (Remove), проверки, является ли очередь
пустой (Empty)).
procedure Search2(k: integer);
begin
Insert(k); {помещаем в очередь номер
начальной вершины}
M[k]:=1;
while not Empty do {пока в очереди есть
подлежащие обработке вершины,}
begin {просматриваем их}
v:=Remove; {берем очередную
вершину из очереди,}
Просмотреть(v); {просматриваем ее}
for t:=1 to N do
if (C[v,t]=1) and (M[t]=0) {все смежные
с ней вершины,}
then begin {которые не были
еще просмотрены,}
Insert(t); {добавляем в}
M[t]:=1; {очередь просмотра}
end;
end;
end;
С подобного рода алгоритмами мы встречались и ранее:
вспомните алгоритм обхода лабиринта, где мы помечали про-
смотренные клетки. При этом число, которое записано в клетке
лабиринта, означало длину кратчайшего маршрута от начальной
клетки до данной.
Аналогичное утверждение верно и для графа. Просмотрен-
ные вершины мы пока что помечали единицами, остальные – ну-
лями. Способ пометки можно несколько модифицировать: будем
помечать вершины, которые еще не просмотрели, числами –1, а
просмотренные вершины – отличными от –1 числами. При этом
начальную вершину можно пометить нулем, а остальные поме-
чать следующим способом: если вершина помечена числом k, то
смежные с ней вершины (которые мы еще не просмотрели) будем
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
19
помечать числом k+1 и добавлять в очередь просмотра. Алгоритм
модифицируется следующим образом:
procedure Search3(k: integer);
begin
for t:=1 to N do M[k]:=-1;
Insert(k); {помещаем в очередь
номер начальной вершины}
M[k]:=0; {помечаем ее нулем}
while not Empty do {пока в очереди есть
подлежащие обработке вершины}
begin {просматриваем их}
v:=Remove; {берем очередную
вершину из очереди}
Просмотреть(v); {просматриваем ее}
for t:=1 to N do
if (C[v,t]=1) and (M[t]=-1)
{все смежные с ней вершины,}
then begin {которые не были
еще просмотрены,}
Insert(t); {добавляем в
очередь просмотра}
M[t]:=M[v]+1; {и помечаем}
end;
end;
end;
В результате работы этого алгоритма пометки будут иметь
следующий смысл: если вершина помечена числом k, то расстоя-
ние (длина кратчайшего пути) от начальной вершины до данной
равно k. Если граф был несвязным, то некоторые вершины так и
останутся помеченными числом –1. Поэтому данный алгоритм
(да и первый алгоритм поиска в ширину тоже) можно использо-
вать для проверки связности графа.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
20
Поиск кратчайшего пути
между двумя вершинами
Постановка задачи
Решим следующую задачу: имеется несколько городов, неко-
торые из которых соединены дорогами, причем длины дорог из-
вестны. Требуется найти длину кратчайшего пути между двумя
выбранными городами.
Конечно, можно было бы предложить перебрать все возмож-
ные пути между выбранными городами, после чего выбрать из
них кратчайший. Но сразу ясно, что такой способ хорошим никак
назвать нельзя. Во-первых, сложность состоит в самом переборе
путей, а во-вторых, не стоит рассчитывать на оптимальность та-
кого переборного алгоритма. Поэтому для решения этой задачи
мы будем использовать более эффективные алгоритмы.
Для начала сформулируем данную задачу на языке теории
графов. Итак, у нас есть связный граф с N вершинами (то есть, из
любой вершины можно попасть в любую другую). Каждое ребро
имеет определенный вес. Веса удобно записывать в матрицу
смежности – двумерный массив C (NxN), при этом элемент
C[i,j] – вес ребра, соединяющего вершины с номерами i и j.
Граф, в котором ребрам приписаны веса, называется взве-
шенным.
Также удобно считать, что если две вершины не соединены
ребром, то вес ребра между этими вершинами равен бесконечно-
сти. Иначе говоря, добавляем отсутствующие ребра, дополняя
граф до полного графа (в котором все вершины попарно соедине-
ны), при этом добавляемые ребра (те, которых не было в исход-
ном графе) получают бесконечный вес. В качестве "бесконечно-
сти" можно использовать очень большое целое число (например,
такое число, которое больше суммы весов всех ребер в исходном
графе). Петлям (ребрам, идущим из вершины в саму эту верши-
ну) можно приписать вес 0.
Так как между отмеченными вершинами существует путь, то
при добавлении таких фиктивных ребер (с бесконечными весами)
мы "не испортим" результат. Действительно: кратчайший путь не
может содержать ребро бесконечного веса, так как существует
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
21
путь короче (просто произвольный путь между отмеченными
вершинами по имеющимся в исходном графе ребрам).
Весом (длиной) пути будем называть сумму весов всех вхо-
дящих в путь ребер. Требуется найти длину кратчайшего пути
между двумя заданными вершинами графа. Длину кратчайшего
пути между вершинами будем также называть расстоянием.
Для решения задачи нахождения длины кратчайшего пути
между вершинами обычно используют алгоритмы Дейкстры и
Форда – Беллмана.
Алгоритм Дейкстры
Рассматриваемый алгоритм (алгоритм Дейкстры) решает бо-
лее общую задачу: пусть в графе выделена некоторая вершина.
Тогда найдем кратчайшие расстояния от данной вершины до всех
остальных вершин графа. Если нам нужно найти кратчайшее рас-
стояние между двумя заданными вершинами, то можно взять
первую вершину, применить для графа с данной выделенной
вершиной алгоритм Дейкстры, после чего выбрать из получен-
ных данных расстояние от первой вершины до второй.
Очевидна некоторая избыточность: возможно, нам и не нуж-
но находить расстояния от данной вершины до всех остальных, а
интересует путь только лишь между двумя заданными вершина-
ми. Однако эффективных алгоритмов, которые находят лишь
нужный нам путь (и не решают указанную выше общую задачу)
пока не известно.
Пусть выделена некоторая вершина v. В ходе работы алго-
ритма Дейкстры будем заполнять массив D кратчайших расстоя-
ний от вершины v до всех остальных вершин в графе. В итоге для
каждого значения k от 1 до N в элементе D[k] будет содержаться
кратчайшее расстояние между вершинами v и k.
В ходе работы алгоритма также будем помечать некоторые
вершины. В начале работы алгоритма помечена только начальная
вершина (первая), в конце работы оказываются помеченными все
вершины. При этом на каждом шаге работы алгоритма для каж-
дой помеченной вершины хранится длина самого короткого пути
между первой вершиной и данной, причем известно, что путь
минимальной длины проходит только через помеченные города.
А для каждой непомеченной вершины хранится наименьшая
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
22
длина среди всех путей от первой вершины до данной, в которых
в качестве промежуточных используются помеченные города.
Иначе говоря, хранимое для непомеченной вершины число пока-
зывает, какое наименьшее расстояние нужно преодолеть от вер-
шины 1 до данной, если в качестве промежуточных можно ис-
пользовать только помеченные вершины.
Все эти числа можно хранить в массиве D. Данные хранимые
величины будем называть оценками длин кратчайших путей.
Оценки кратчайших путей для помеченных вершин являются
точными, а для непомеченных требуют корректировки при каж-
дой пометке очередной вершины.
На каждом шаге алгоритма будем добавлять к множеству
помеченных вершин еще одну вершину, а для непомеченных
вершин будем корректировать оценки кратчайших путей. Выбор
очередной вершины осуществляется следующим образом: рас-
смотрим все непомеченные вершины, выберем из них ту, для ко-
торой оценка длины кратчайшего пути минимальна (пусть это
вершина z), и пометим ее. Легко убедиться в том, что данная
оценка кратчайшего пути до вершины z является точной. Дейст-
вительно, если рассмотреть путь, содержащий какую-нибудь не-
помеченную вершину w, то уже до вершины w путь будет длин-
нее, чем рассматриваемая оценка кратчайшего пути, а ведь от w
нужно дойти до вершины z.
После того как вершина z будет помечена, требуется скор-
ректировать оценки кратчайших расстояний до непомеченных
вершин. Сделать это не очень сложно: кратчайшее расстояние до
непомеченной вершины может содержать вершину z, а может и
не содержать ее. Длина кратчайшего пути, проходящего за все
помеченные вершины, кроме z, уже известны. А среди остальных
путей с промежуточными помеченными вершинами можно рас-
смотреть лишь те, в которых вершина z (последняя помеченная)
является последней промежуточной вершиной.
Данную операцию повторяем до тех пор, пока не будут по-
мечены все вершины.
Учитывая все сказанное выше, алгоритм Дейкстры поиска
длины кратчайшего пути от вершины v до остальных вершин
можно описать следующим образом:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
23
Шаг 1:
Для k от 1 до N: D[k]:=C[v,k]; {начальные оценки
длины путей}
M:=[1..N]-[v]; {множество непомеченных
вершин}
Пока M не пусто выполнять шаг 2.
Шаг 2:
w – непомеченная вершина оценка длины пути мини-
мальна; {D[w] минимальна среди всех D[k] для непоме-
ченных k}
M := M-[w]; {исключаем w из множества непомечен-
ных вершин}
Для всех k из множества M:
D[k] := min{D[k],D[w]+C[w,k]};
После заполнения массива D достаточно выбрать из него
кратчайшее расстояние от вершины v до любой другой вершины.
Покажем работу алгоритма Дейкстры на примере. Рассмот-
рим следующий граф:
Рис. 8. Взвешенный граф
Матрица весов C для данного графа выглядит следующим
образом:
0 7 5 ∞ ∞ ∞ ∞ ∞
7 0 9 4 ∞ 6 ∞ ∞
5 9 0 7 8 ∞ ∞ ∞
∞ 4 7 0 6 ∞ 9 ∞
∞ ∞ 8 6 0 ∞ 8 ∞
∞ 6 ∞ ∞ ∞ 0 11 7
∞ ∞ ∞ 9 8 11 0 6
∞ ∞ ∞ ∞ ∞ 7 6 0
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
24
Будем искать расстояния от вершины с номером 1 до всех
остальных вершин. В начале работы алгоритма массив D (массив
оценок кратчайших путей) заполняем просто длинами ребер от
первой вершины до каждой из оставшихся вершин:
D = [0, 7, 5, ∞, ∞, ∞, ∞, ∞]
Помеченной является пока только первая вершина. Заметим,
что оценка расстояния до нее является точной: она равна нулю и
меньше быть не может.
Теперь начинаем помечать и остальные вершины. Среди всех
непомеченных вершин (а ими пока являются все вершины, кроме
первой) выбираем ту, для которой оценка длины кратчайшего пу-
ти минимальна (фактически, выбираем минимальный из элемен-
тов массива D, соответствующий непомеченным вершинам).
Такой является вершина с номером 3 (а соответствующая
оценка равна 5). Помечаем эту вершину и начинаем пересчиты-
вать оценки расстояний. Оценка либо останется прежней (пока
кратчайший путь проходит через те же вершины, что и до добав-
ления новой вершины в список помеченных), либо изменилась
(если кратчайший путь проходит через вновь добавленную поме-
ченную вершину). Для этого (в соответствии с алгоритмом) для
всех k, отличных от 1 и 3, в качестве элемента D[k] выбирается
минимум из D[k] (прежнее значение) и D[2]+C[3,k] (новый крат-
чайший путь проходит через добавленную вершину 3).
Итак, оценка расстояния до вершины 2 не изменилась (по-
прежнему короче путь напрямую от вершины 1, нежели "с пере-
садкой" в помеченной вершине 2). Не изменятся оценки длины
кратчайшего пути и до вершин 6, 7, 8: он равен "бесконечности"
как без использования промежуточной вершины 3, так и с ис-
пользованием ее в качестве "перевалочного пункта".
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
25
А вот оценки расстояний до вершин 4 и 5 изменятся. Дейст-
вительно, длина прямого пути от вершины 1 до вершины 4 была
равена "бесконечности", а теперь проще будет добраться до нее
через вершину 3 и оценка кратчайшего пути равна 5 + 7 = 12.
Иначе говоря, D[4] := min{D[4], D[3]+C[3,4]} = min{∞, 5+7} =
min{∞,12} = 12. Аналогично меняется оценка длины кратчайшего
пути до вершины 5 – она теперь равна 13 (путь через вершину 3).
После пересчета оценок расстояний (длин кратчайших пу-
тей) граф и массив D выглядят так:
D = [0, 7, 5, 12, 13, ∞, ∞, ∞]
Снова ищем вершину для того, чтобы ее пометить. Для этого
в массиве D выбираем наименьший из тех элементов, которые не
соответствуют помеченным вершинам (это все элементы, кроме
первого и третьего). Таким элементом будет второй: для него
оценка расстояния равна 7. Помечаем его и пересчитываем оцен-
ки расстояний.
Для вершин 7 и 8 они не изменятся (как были равны беско-
нечности, так и будут). До вершины 5 по-прежнему короче путь
через вершину 3, нежели через добавленную вершину 2. А оцен-
ки расстояний до вершин 4 и 6 необходимо скорректировать: до
вершины 4 короче оказывается путь через вершину 2 (был равен
12, стал равен 11), а до вершины 6 оценка расстояния была равна
бесконечности, а теперь в нее можно попасть через вершину 2 (и
соответствующее расстояние равно 13). После этого имеем сле-
дующий граф матрицу оценок:
D = [0, 7, 5, 11, 13, 13, ∞, ∞]
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
26
Продолжаем помечать вершины. Из массива D выбираем
элемент с номером 4 (для соответствующей вершины оценка рас-
стояния оказывается наименьшей среди непомеченных). Помеча-
ем ее, выполняем пересчет оценок расстояний:
D = [0, 7, 5, 11, 13, 13, 20, 21]
Помечать вершины продолжаем до тех пор, пока все они не
окажутся помеченными. Стоит обратить внимание на то, что
оценки для помеченных вершин являются точными и не меняют-
ся при пометке новых вершин.
Итак, на следующем шаге можно пометить либо вершину 5,
либо вершину 6 (пятый и шестой элементы массива D одинаковы
и равны 13, поэтому можно выбрать любую из данных вершин).
Пометим вершину 5. С учетом того, что была помечена новая
вершина, осуществляем пересчет оценок расстояний:
D = [0, 7, 5, 11, 13, 13, 20, 21]
Заметим, что при этом массив D не изменился. Это означает,
что пути, проходящие через вершину 5 до непомеченных вершин,
не короче рассмотренных ранее путей, которые эту вершину не
содержат. Далее осталось выбрать минимальный из элементов
массива D с номерами 6, 7, 8 (они соответствуют непомеченным
вершинам). Таким является элемент с номером 6, соответственно
шестую вершину мы и помечаем. При пересчете оценок расстоя-
ний они меняется только оценка длины пути до вершины 8 (те-
перь короче будет путь через вершину 6), остальные остаются без
изменений:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
27
D = [0, 7, 5, 11, 13, 13, 20, 20]
Осталось две непомеченные вершины: 7 и 8. Соответст-
вующие элементы массива оценок D равны, поэтому можно по-
метить любую из них. Пометим вершину 7. Это не изменит мас-
сива оценок расстояний:
D = [0, 7, 5, 11, 13, 13, 20, 20]
Теперь осталась только вершина 8, которую нужно просто
пометить. Так как непомеченных вершин после этого не остается,
то и пересчитывать оценки расстояний не нужно. В результате
получаем следующий граф и массив оценок расстояний (D):
D = [0, 7, 5, 11, 13, 13, 20, 20]
Теперь мы можем определить длину кратчайшего пути от
вершины 1 до любой другой вершины. Например, длина крат-
чайшего пути от вершины 1 до вершины 7 равна 20 (седьмой
элемент массива D). Однако это не дает нам самого пути, а лишь
показывает его длину.
Оценим трудоемкость алгоритма. Работу алгоритма можно
условно разделить на N шагов, на каждом из которых мы помеча-
ем вершину. При пометке вершины мы пересчитываем оценки
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
28
расстояний до вершин, что требует порядка N действий на каж-
дом шаге. Итого получается порядка N 2 действий. Таким обра-
зом, можем сделать вывод, что порядок роста трудоемкости со-
ставляет N 2.
Вообще говоря, ожидать меньшей трудоемкости не представ-
ляется возможным. Действительно, при построении кратчайшего
пути мы должны учитывать все длины (веса) ребер, что требует
просмотра матрицы весов размера NxN, что требует уже порядка
N 2 действий.
Теперь рассмотрим несколько другую ситуацию: пусть на
дорогах между городами установлено одностороннее движение.
В принципе, между двумя городами могут существовать и пря-
мой, и обратный путь, но ничто не мешает им иметь разную дли-
ну (иначе говоря, длина дороги из города v в город w может быть
не равна длине дороги из w в v). В этом случае в матрице весов
элемент C[i,j] может быть не равен элементу C[j,i] (в случае дву-
стороннего движения эти элементы были равны, то есть матрица
была симметричной относительно главной диагонали). Требуется
найти длины кратчайших путей от выделенной вершины до всех
остальных вершин.
Если нет ребра из вершины v до вершины w (ориентирован-
ное ребро чаще называют дугой), то удобно приписывать ему вес,
равный бесконечности.
Понятно, что для решения данной задачи можно использо-
вать тот же самый алгоритм Дейкстры. Обратите внимание, что
при описании алгоритма Дейкстры мы нигде не опирались на
симметричность путей (то есть на равенство C[i,j] = C[j,i]), по-
этому алгоритм будет давать решение и в случае однонаправлен-
ных (ориентированных) дорог.
Граф, в котором каждое из ребер имеет направление, называ-
ется ориентированным. Если каждому из ориентированных ребер
(каждой из дуг) приписан вес, то такой граф называется взвешен-
ным ориентированным графом.
Итак, алгоритм Дейкстры предназначен для поиска длины
кратчайшего пути от выделенной вершины до всех остальных как
в неориентированном ("обычном") графе, так и в ориентирован-
ном, в том случае, если веса ребер (дуг) положительны.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
29
Алгоритм Форда – Беллмана
Рассмотренный выше алгоритм (алгоритм Дейкстры) исполь-
зовал достаточно простую идею: оценками расстояний были дли-
ны кратчайших путей с использованием в качестве промежуточ-
ных вершин только помеченных, а набор помеченных вершин по-
стоянно расширялся до тех пор, пока не охватывал все вершины
графа (при этом все оценки расстояний оказывались точными).
Следующий алгоритм (алгоритм Форда – Беллмана) будет
также основан на достаточно простой идее: будем последова-
тельно находить длины кратчайших путей от выделенной верши-
ны до всех остальных вершин с количеством промежуточных
вершин не более k (последовательно для всех k от 0 до N–2). То-
гда, когда будет рассмотрен случай k = N–2, мы получим точные
оценки. Действительно, кратчайший путь не может содержать
более N–1 ребер (он соответствует случаю N–2 пересадок), иначе
он содержит цикл, а поэтому не будет являться кратчайшим.
Ключевым моментом является переход от наибольшего ко-
личества промежуточных вершин k к количеству k+1. Сделаем
обозначение: пусть D[w,k] – длина кратчайшего пути от выде-
ленной вершины v до вершины w с использованием не более k
пересадок (промежуточных вершин). Тогда каким образом можно
добраться по кратчайшему пути от v до w с использованием не
более k+1 пересадок? Очевидно, что достаточно рассмотреть
имеющийся путь от v до w с использованием не более k переса-
док, а также все пути, состоящие из пути от v до вершины i (i от 1
до N) с добавлением ребра (i, w), после чего выбрать из рассмот-
ренных путей самый короткий.
Итак, имеем:
D[w,k+1] = min{D[w,k], D[i,k]+C[i,w] для всех i от 1 до N}.
Пересчет оценок расстояний продолжаем, пока k не примет
значение N–2. После этого оценки окажутся точными. Алгоритм
можно описать так:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
30
Шаг 1:
k:=0;
Для всех i от 1 до N: D[i,0]:=C[v,i]
{первоначальные оценки расстояний – длины
путей без пересадок}
Пока k<N–1 выполнять шаг 2;
Шаг 2:
Для всех w от 1 до N выполняем следующие
действия:
D[w,k+1]:=min{D[w,k], D[i,k]+C[i,w]
для всех i от 1 до N};
{выполняем пересчет оценок расстояний}
k:=k+1; {увеличиваем k на 1}
Понятно, что аналогичный алгоритм можно применить и для
нахождения длины кратчайшего пути во взвешенном ориентиро-
ванном графе.
Итак, алгоритм Форда – Беллмана также основан на доста-
точно простой идее. Однако (в отличие от алгоритма Дейкстры)
этот алгоритма имеет достаточно высокую трудоемкость: она со-
ставляет порядка N 3 (где N – количество вершин в графе), по-
этому проигрывает по трудоемкости алгоритму Дейкстры.
Поиск длин кратчайших путей между
всеми вершинами. Алгоритм Флойда
Рассмотренные выше алгоритмы были предназначены для
поиска длины кратчайшего пути между двумя выделенными
вершинами. В качестве "побочного продукта" они давали длины
кратчайших путей от выделенной вершины до всех остальных
вершин графа.
Решим еще более общую задачу: найдем длины кратчайших
путей между каждой парой вершин в графе (без разницы, являет-
ся он ориентированным или нет). В принципе, можно было бы,
последовательно выбирая в качестве начальной все вершины
графа, N раз применить алгоритм Дейкстры (добившись оценки
трудоемкости порядка N3
). Но на практике обычно используют
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
31
другой алгоритм с тем же порядком роста трудоемкости – алго-
ритм Флойда.
Данный алгоритм также основан на идее последовательного
пересчета оценок расстояний. Обозначим через D[i,j,k] длину
кратчайшего пути из вершины i в вершину j с использованием
промежуточных вершин из множества [1,…,k] (то есть, с номе-
рами от 1 до k). Переход от D[i,j,k] к D[i,j,k+1] осуществляется
следующим образом: кратчайший путь с промежуточными вер-
шинами 1, …, k+1 может не содержать вершины k (тогда он ра-
вен D[i,j,k]), а может содержать, тогда он разбивается на крат-
чайший путь от вершины i до вершины с номером k+1 и на крат-
чайший путь от вершины k+1 до вершины j. Учитывая сказанное
выше, формулу пересчета можно записать так:
D[i,j,k+1] = min{ D[i,j,k], D[i,k+1,k]+ D[k+1,j,k]}.
Алгоритм можно записать следующим образом:
Шаг 1:
Для всех i от 1 до N и для всех j от 1 до N
выполняем: D[i,j,0] := C[i,j];
{начальные оценки расстояний}
Шаг 2:
Для всех k от 1 до N выполняем следующие
действия:
Для всех х i от 1 до N
и для всех j от 1 до N выполняем:
D[i,j,k+1]=min{D[i,j,k];D[i,k+1,k]+D[k+1,j,k]}
В результате работы данного алгоритма длины кратчайших
расстояний между вершинами i и j будут находиться в элементах
D[i,j,N]. Понятно, что можно оценки все время хранить в одном и
том же двумерном массиве D.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
32
Деревья
Основные определения
Одним из частных случаев графов является дерево. С этим
понятием мы уже сталкивались в главе "Структуры данных", ко-
гда работали с бинарными деревьями. Действительно, приведен-
ную тогда схему можно считать графом, в котором узлы дерева
являются вершинами графа, а узел соединяется с потомками реб-
рами. При этом от любого узла по таким ребрам можно добраться
до любого другого (более формально это означает, что рассмат-
риваемый граф является связным), причем единственным спосо-
бом. Однако слово "бинарное", очевидно, уже предполагает неко-
торое дополнительное условие, накладываемое на дерево. Дадим
определение дерева в общем виде.
Дерево – это связный граф без циклов. Несложно убедиться в
том, что бинарное дерево является деревом и по только что при-
веденному определению. Примерами деревьев являются и моле-
кулы некоторых химических веществ, например предельных уг-
леводородов, при этом атомы являются вершинами, а связи меж-
ду ними – ребрами (именно с рассмотрения такого рода графов в
середине XIX века и началось активное изучение деревьев и их
свойств). Пример дерева приведен на рисунке 1.
Рис. 9. Пример дерева
Данное выше определение дерева не является единствен-
ным. Приведем еще несколько эквивалентных определений (эк-
вивалентность в данном случае означает, что из любого приве-
денного определения можно получить другое):
• Дерево – это связный граф, в котором любые две вер-
шины соединены единственным простым путем.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
33
• Дерево – это связный граф, в котором количество
ребер на 1 меньше количества вершин.
• Дерево – это граф без циклов, в котором количество
ребер на 1 меньше количества вершин.
• Дерево – это граф без циклов, в котором при соедине-
нии любой пары несмежных вершин образуется цикл.
И этот список можно продолжать. С другой стороны, приве-
денные выше определения можно рассматривать как свойства де-
ревьев.
Понятно, что дерево можно получить из любого связного
графа. Для этого можно выполнить следующие действия: пока
граф содержит циклы, выбираем один из них и удаляем в нем од-
но из ребер. Например, если есть связная сеть дорог, соединяю-
щая несколько городов, то пока эта сеть содержит циклы, мы мо-
жем закрывать входящие в циклы дороги (по одной). Понятно,
что при этом граф остается связным. Действительно, если произ-
вольные две вершины (два города) были соединены путем, то по-
сле удаления ребра (дороги) эти вершины все равно оказываются
связанными путем: если путь проходил через удаленное ребро,
которое входило в цикл, то из одной вершины в другую все равно
существует путь "в объезд" удаленного ребра.
Полученное дерево, очевидно, будет содержать те же самые
вершины, что и исходный граф, а ребра дерева являлись изна-
чально ребрами исходного графа. Такого рода дерево называется
остовом (или каркасом).
Понятно, что остовов в графе может быть несколько. На ри-
сунке 10 приведен пример графа (1) и нескольких его остовов (2,
3 и 4):
Рис. 10. Граф и его остовы
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
34
В графе с достаточно большим количеством ребер остовов
может быть очень и очень много. Одной из задач будет нахожде-
ние среди всего множества остовов тех, которые обладают опре-
деленным свойством. Решением такого рода задач мы сейчас и
займемся.
Остов минимального веса
Рассмотрим следующую задачу. Пусть есть некоторый набор
деревень, между некоторыми из которых проложены грунтовые
дороги, образующие связную систему (то есть из любой деревни
можно добраться до любой другой, возможно, "транзитом" через
какие-то промежуточные деревни). Для того чтобы обеспечить
связь между деревнями в межсезонье (когда грунтовые дороги
становятся неприспособленными для езды), решено некоторые из
грунтовых дорог покрыть асфальтом так, чтобы из любой дерев-
ни можно было проехать до любой другой, используя только за-
асфальтированные дороги. При этом стоимость асфальтирования
разных дорог может быть различной (например, зависеть от дли-
ны дороги и особенностей рельефа). Наша задача: построить
связную систему асфальтированных дорог с наименьшими рас-
ходами.
Переведем условие задачи на язык теории графов. Итак, де-
ревни можно считать вершинами, а грунтовые дороги между ни-
ми – ребрами. Так как из любой деревни можно было проехать до
любой другой, то такой граф является связным. Также мы имеем
некоторую дополнительную информацию: знаем, сколько стоит
асфальтирование каждой из дорог. В этом случае говорят, что
каждому ребру приписан определенный вес (а граф называется
взвешенным):
Рис. 11. Взвешенный граф
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
35
Чаще всего веса ребер заносятся в двумерный массив, кото-
рый называется матрицей весов: в ячейку на пересечении i-й
строки и j-го столбца записывают вес ребра между i-й и j-й вер-
шиной. Иногда для удобства считают, что в графе каждая верши-
на соединена с каждой, но вес несуществующих в исходном гра-
фе ребер равен бесконечности. Применительно к задаче об ас-
фальтировании дорог это можно сформулировать так: постройка
асфальтированной дороги между двумя деревнями, не соединен-
ными между собой грунтовой дорогой, требует бесконечных (или
крайне больших) затрат. Для графа, приведенного на рисунке 3,
матрица весов будет иметь следующий вид (символом "∞" обо-
значен бесконечный вес ребра):
0 8 6 8 ∞
8 0 6 ∞ ∞
6 6 0 5 7
8 ∞ 5 0 10
∞ ∞ 7 10 0
Рис. 12. Матрица весов
Такие "несуществующие" ребра (дороги) с бесконечными ве-
сами, как легко заметить, не будут входить в искомую минималь-
ную сеть дорог. Действительно, наличие в сети такого ребра авто-
матически делает ее общую стоимость бесконечной, но понятно,
что мы можем построить сеть асфальтированных дорог с меньши-
ми затратами, просто взяв совершенно произвольный остов.
Почему же сеть дорог минимальной стоимости мы будем ис-
кать именно среди остовов? Ответ достаточно очевиден. Дейст-
вительно, полученная сеть дорог должна связывать все деревни
друг с другом, поэтому мы должны найти связный граф. Также
эта сеть дорог минимальной не должна содержать циклов, иначе
мы могли бы выбросить одну из дорог (то есть не асфальтировать
одну из грунтовых дорог) в данном цикле и получить сеть дорог
меньшей стоимости. Итак, искомая сеть дорог минимальной
стоимости действительно должна быть связным графом без цик-
лов, то есть деревом. А так как это дерево содержит все вершины
(соединяет все деревни), то это остов.
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
36
Таким образом, задачу можно сформулировать следующим
образом: в заданном взвешенном графе найти остов минимально-
го веса. Рассмотрим два способа решения данной задачи: алго-
ритм Прима и алгоритм Краскала.
Алгоритм Прима
Идея алгоритма достаточно проста. Будем строить остов, по-
степенно добавляя по одному ребру. Первым в остов включаем
ребро с наименьшим весом (в нашей задаче: асфальтируем ту до-
рогу, покрытие которой асфальтом потребует наименьших за-
трат). Далее на каждом шаге присоединяем к сети не рассмотрен-
ное ранее ребро минимального веса, причем выбираем мини-
мальное среди тех ребер, добавление которых к сети не образует
цикла.
Иначе говоря, на каждом шаге мы имеем дерево, к которому
присоединяем ребро (с вершиной) так, чтобы полученная сеть ос-
тавалась деревом, причем добавляем наиболее "легкое" из таких
ребер.
Как добиться того, чтобы при добавлении ребра не образовы-
вался цикл? Очевидно, для этого мы должны проводить ребро от
уже построенной сети к одной из тех вершин, которые мы еще не
рассматривали.
Представим себе рабочих, которые асфальтируют дороги по
данному алгоритму. В самом начале работы они заасфальтирова-
ли дорогу, затраты на покрытие асфальтом которой самые низкие
(то есть покрыли асфальтом одну из дорог, затратив на это мини-
мум средств), соединив таким образом какие-то две деревни. А
дальше они смотрят, какую деревню из тех, до которых еще не
достроена сеть асфальтированных дорог, можно было бы присое-
динить к сети с наименьшими затратами. Дорога, обладающая
данными условиями, покрывается асфальтом, после чего рабочие
снова ищут новую деревню, чтобы присоединить к сети, "протя-
нув" к ней дорогу. Эту операцию последовательно проделывают
до тех пор, пока все деревни не окажутся присоединенными к се-
ти асфальтированных дорог.
Может возникнуть вполне естественный вопрос: находит ли
этот алгоритм действительно остов минимального веса. Да, нахо-
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
37
дит, и это можно строго доказать. Однако на этом мы останавли-
ваться не будем.
Вместо этого уделим некоторое внимание организации поис-
ка нового добавляемого ребра. Действительно, эту операцию
приходится проделывать на каждом шаге алгоритма. Добавляе-
мое ребро соединяет одну из рассмотренных ранее вершин с од-
ной из нерассмотренных. Поэтому кажется вполне естественным
ввести два множества: множество рассмотренных вершин (X) и
множество нерассмотренных вершин (Y). Перед началом работы
алгоритма множество X пусто, а Y содержит все вершины (дей-
ствительно, мы ведь еще не рассмотрели ни одну из вершин). На
первом шаге (при включении в сеть первого ребра) в множество
X включаем две вершины, связанные добавляемым ребром наи-
меньшего веса, и, соответственно, исключаем эти две вершины из
множества Y. А далее на каждом шаге мы делаем следующее:
рассматриваем все ребра, соединяющие вершины множества X с
вершинами множества Y, и выбираем из них то, которое имеет
меньший вес. Пусть оно соединяет вершину x (из множества X) с
вершиной y (из Y). Добавляем ребро (x, y) к сети, вершину y до-
бавляем к множеству X и исключаем из множества Y. Так про-
должаем делать до тех пор, пока в множестве Y не останется
вершин.
Множества X и Y можно организовать с помощью списков,
массивов или переменных множественного типа.
Как же найти ребро минимального веса среди тех, которые
соединяют множество X с множеством Y? Для решения этой за-
дачи можно рассмотреть те элементы матрицы весов, которые
стоят на пересечении строк с номерами из X и столбцов с номе-
рами из Y, и найти среди них наименьший. Иначе говоря, ищем
наименьший элемент в таблице, получающейся из матрицы весов
исходного графа выкидыванием всех строк с номерами, не со-
держащимися в X, и столбцов с номерами, не содержащимися в
Y. Если такой элемент находится в строке с номером x и столбце
с номером y, то ребро (x,y) – искомое.
Обобщая изложенное выше, алгоритм Прима можно в общих
чертах описать следующим образом:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
38
X – пустое множество;
Y – содержит все вершины;
Найти в матрице весов наименьший элемент:
x = номер соответствующей строки,
y = номер столбца;
Добавить ребро (x,y) в сеть;
Добавить x и y в X;
Исключить x и y из Y;
while (Y не пусто) do
begin
Найти в матрице весов наименьший из элементов на
пересечении строк с номерами из X и столбцов с но-
мерами из Y:
x = номер строки, y = номер столбца;
Добавить ребро (x,y) в сеть;
Добавить y в X;
Исключить y из Y;
end;
Проследим ход выполнения алгоритма Прима на примере.
Пусть имеется сеть дорог следующего вида:
Вначале множество X пусто, множество Y содержит все вер-
шины:
X = {}; Y = {1, 2, 3, 4, 5, 6, 7}.
Начинаем построения остова минимального веса с выбора
самого "легкого" ребра. Этим свойством обладает ребро, соеди-
няющее вершины 1 и 5 (его вес равен 5). Добавляем его к остову,
а вершины 1 и 5 добавляем к множеству X, исключив их при этом
из множества Y:
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
39
X = {1, 5}; Y = {2, 3, 4, 6, 7}
Теперь посмотрим, какую вершину можно было бы соеди-
нить ребром с имеющейся сетью, затратив при этом минимум
средств. Для этого рассмотрим все ребра с одной вершиной из
множества X, а второй – из множества Y. Таких ребер у нас три:
(1,2), (5, 4) и (5, 6). Из них выберем ребро наименьшего веса – это
ребро (1,2). Добавляем это ребро к остову, а вершину 2 добавляем
в множество X и исключаем из множества Y:
X = {1, 2, 5}; Y = {3, 4, 6, 7}
Снова ищем среди ребер, соединяющих вершины множества
X с вершинами множества Y, то, которое имеет наименьший вес.
Среди таких ребер ((2,3); (2,4); (5,4) и (5,6)) наименьший вес (9)
имеет ребро (2,3), которое мы и добавляем к остову. Вершина 3 в
свою очередь добавляется к X и исключается из Y:
X = {1, 2, 3, 5}; Y = {4, 6, 7}
Вершины множества X соединяют с вершинами множества Y
следующие ребра: (2,4), (3,4), (3,6), (3,7), (5,4) и (5,6). Наимень-
шим весом среди них (6) обладает ребро (3,7). Его включаем в
Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие
422.методы построения эффективных алгоритмов  учебное пособие

More Related Content

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

Геометрия помогает считать
Геометрия помогает считатьГеометрия помогает считать
Геометрия помогает считатьGarik Yenokyan
 
Задворный б.в. (минск) от идеи к исследованию
Задворный б.в. (минск)   от идеи к исследованиюЗадворный б.в. (минск)   от идеи к исследованию
Задворный б.в. (минск) от идеи к исследованиюЛёха Гусев
 
Задворный б.в. (минск) от идеи к исследованию
Задворный б.в. (минск)   от идеи к исследованиюЗадворный б.в. (минск)   от идеи к исследованию
Задворный б.в. (минск) от идеи к исследованиюЛёха Гусев
 
558 1 математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с
558 1  математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с558 1  математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с
558 1 математика. 9кл.-латотин, чеботаревский_минск, 2014 -397сdfdkfjs
 
8 геом ершова_голобородько_2008_рус
8 геом ершова_голобородько_2008_рус8 геом ершова_голобородько_2008_рус
8 геом ершова_голобородько_2008_русAira_Roo
 
Geometrija 8-klas-ershova-2008-ros
Geometrija 8-klas-ershova-2008-rosGeometrija 8-klas-ershova-2008-ros
Geometrija 8-klas-ershova-2008-roskreidaros1
 
8 геом єршова_голобородько_2011_укр
8 геом єршова_голобородько_2011_укр8 геом єршова_голобородько_2011_укр
8 геом єршова_голобородько_2011_укрAira_Roo
 
11 geom e_ru
11 geom e_ru11 geom e_ru
11 geom e_ruUA1011
 
Графический метод
Графический методГрафический метод
Графический методlarionvvs
 
"Почему голова круглая?" Внеурочная деятельность 2 класс
"Почему голова круглая?" Внеурочная деятельность 2 класс"Почему голова круглая?" Внеурочная деятельность 2 класс
"Почему голова круглая?" Внеурочная деятельность 2 классknopochka-malishka
 
презентация проекта графио о графах
презентация проекта графио о графахпрезентация проекта графио о графах
презентация проекта графио о графах67921340AB
 
11 геом ершова_голобородько_2012_рус
11 геом ершова_голобородько_2012_рус11 геом ершова_голобородько_2012_рус
11 геом ершова_голобородько_2012_русAira_Roo
 

Similar to 422.методы построения эффективных алгоритмов учебное пособие (20)

8 a mak_2013
8 a mak_20138 a mak_2013
8 a mak_2013
 
8 a mak_2013
8 a mak_20138 a mak_2013
8 a mak_2013
 
Геометрия помогает считать
Геометрия помогает считатьГеометрия помогает считать
Геометрия помогает считать
 
Задворный б.в. (минск) от идеи к исследованию
Задворный б.в. (минск)   от идеи к исследованиюЗадворный б.в. (минск)   от идеи к исследованию
Задворный б.в. (минск) от идеи к исследованию
 
Задворный б.в. (минск) от идеи к исследованию
Задворный б.в. (минск)   от идеи к исследованиюЗадворный б.в. (минск)   от идеи к исследованию
Задворный б.в. (минск) от идеи к исследованию
 
127_1
127_1127_1
127_1
 
558 1 математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с
558 1  математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с558 1  математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с
558 1 математика. 9кл.-латотин, чеботаревский_минск, 2014 -397с
 
8 геом ершова_голобородько_2008_рус
8 геом ершова_голобородько_2008_рус8 геом ершова_голобородько_2008_рус
8 геом ершова_голобородько_2008_рус
 
Geometrija 8-klas-ershova-2008-ros
Geometrija 8-klas-ershova-2008-rosGeometrija 8-klas-ershova-2008-ros
Geometrija 8-klas-ershova-2008-ros
 
8 геом єршова_голобородько_2011_укр
8 геом єршова_голобородько_2011_укр8 геом єршова_голобородько_2011_укр
8 геом єршова_голобородько_2011_укр
 
712
712712
712
 
33786
3378633786
33786
 
csdcsv
csdcsvcsdcsv
csdcsv
 
11 geom e_ru
11 geom e_ru11 geom e_ru
11 geom e_ru
 
Графический метод
Графический методГрафический метод
Графический метод
 
531
531531
531
 
"Почему голова круглая?" Внеурочная деятельность 2 класс
"Почему голова круглая?" Внеурочная деятельность 2 класс"Почему голова круглая?" Внеурочная деятельность 2 класс
"Почему голова круглая?" Внеурочная деятельность 2 класс
 
714
714714
714
 
презентация проекта графио о графах
презентация проекта графио о графахпрезентация проекта графио о графах
презентация проекта графио о графах
 
11 геом ершова_голобородько_2012_рус
11 геом ершова_голобородько_2012_рус11 геом ершова_голобородько_2012_рус
11 геом ершова_голобородько_2012_рус
 

More from ivanov15548 (20)

100206
100206100206
100206
 
100221
100221100221
100221
 
100201
100201100201
100201
 
100200
100200100200
100200
 
100208
100208100208
100208
 
100202
100202100202
100202
 
100203
100203100203
100203
 
100205
100205100205
100205
 
100210
100210100210
100210
 
100207
100207100207
100207
 
100209
100209100209
100209
 
100211
100211100211
100211
 
100212
100212100212
100212
 
100218
100218100218
100218
 
100215
100215100215
100215
 
100219
100219100219
100219
 
100214
100214100214
100214
 
100217
100217100217
100217
 
100216
100216100216
100216
 
100222
100222100222
100222
 

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

  • 1. 1 Министерство образования и науки Российской Федерации Федеральное агентство по образованию Ярославский государственный университет им. П. Г. Демидова С.Г. Волченков, Ю.В. Богомолов Методы построения эффективных алгоритмов Учебное пособие Рекомендовано Научно-методическим советом университета для студентов специальности Математическое обеспечение и администрирование информационных систем Ярославль 2005 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 2. 2 УДК 510.5 ББК В127я73 В 68 Рекомендовано Редакционно-издательским советом университета в качестве учебного издания. План 2005 года Рецензенты: кандидат педагогических наук Н.Л. Дашниц; кафедра теории и методики обучения информатике Ярославского государственного педагогического университета им. К.Д. Ушинского В 68 Волченков, С.Г., Богомолов, Ю.В. Методы построения эф- фективных алгоритмов : учебное пособие / С.Г. Волченков, Ю.В. Богомолов ; Яросл. гос. ун-т. – Ярославль : ЯрГУ, 2005. – 146 с. ISBN 5-8397-0401-6 Учебное пособие (продолжение одноименного учебного по- собия, изданного в 2004 г.) посвящено различным аспектам по- строения и анализа эффективных алгоритмов решения некото- рых задач. Материал разбит на главы по предметным областям и по методам решения задач. Главы посвящены геометрическим методам в задачах информатики, рекурсии, динамическому про- граммированию и структурам данных. Пособие рассчитано на студентов факультетов информатики и вычислительной техники, обучающихся по специальности 351500 Математическое обеспечение и администрирование ин- формационных систем (дисциплина "Методы построения эффек- тивных алгоритмов", блок ДС), очной формы обучения, а также может оказаться интересным для школьников, принимающих участие в олимпиадах по информатике. УДК 510.5 ББК В127я73 ISBN 5-8397-0401-6 © Ярославский государственный университет, 2005 © С.Г. Волченков, Ю.В. Богомолов, 2005 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 3. 3 Предисловие Данное пособие не претендует на описание всех суще- ствующих методов построения эффективных алгоритмов. Достаточно сказать, что учебник по алгоритмам, недавно выпущенный в Массачусетском технологическом институте [1] и переведенный на русский язык, содержит 955 страниц! И этот учебник, в свою очередь, тоже далеко не полон. Счи- тается, что относительной полнотой обладает трёхтомник Д. Кнута [2], правда, в нём очень сильно ограничен круг рассматриваемых вопросов, но те, что рассматриваются, ра- зобраны чрезвычайно пунктуально и интересно. Также су- ществуют учебники и монографии, которые, как правило, либо узкоспециализированны, либо, напротив, пытаясь ох- ватить возможно более широкий круг алгоритмов, носят по- верхностный характер и не содержат достаточного круга за- дач [3 – 7, 9 – 13]. Создалась парадоксальная ситуация, ко- гда при относительно широком освещении рассматривае- мой тематики литература, которую можно было бы реко- мендовать для изучения в рамках соответствующего учеб- ного курса, труднодоступна. Предлагаемое учебное пособие является продолжением пособия, изданного в 2004 году. В нем рассмотрены методы построения алгоритмов на графах, алгоритмов сортировки и поиска, а также рассматриваются вопросы переключения алгоритмов. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 4. 4 Глава 1 Алгоритмы на графах Введение В одной из компьютерных игр как-то встретилась такая голо- воломка. На неровной шахматной доске, состоящей из 10 клеток (рис.1), расположены два белых и два черных коня. Требуется поменять коней местами, т.е. расположить белых на места чер- ных и наоборот. Коней разрешается переставлять по правилам шахматной игры, т.е. передвигать "буквой Г" на любую свобод- ную клетку. За один ход можно передвинуть одного коня. Рис. 1 Несколько попыток решить задачу сходу ни к чему не приве- ли. Вооружившись карандашом и бумагой, я попытался фиксиро- вать промежуточные положения коней, но скоро убедился, что записей стало катастрофически много. Вздохнув и призвав на помощь знания ранее встречавшихся головоломок и задач, я стал строить математическую модель задачи. Во-первых, я обозначил клетки доски числами от 1 до 10 и соединил отрезками центры клеток, которые связаны друг с другом ходом коня. Получился рисунок, содержащий всевозможные траектории передвижения коней по доске (рис. 2) • • • • • • • • Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 5. 5 • •0 Рис. 2 Теперь можно было заметить, что траектории движения ко- ней довольно сильно запутаны, и в них трудно разобраться. Рас- путать их было несложно, разместив числа, соответствующие клеткам, в другом порядке: так чтобы клетки, соединенные друг с другом, были размещены рядом. Получился рисунок 3. Рис. 3 Теперь на получившейся схеме отметим коней: белых – кру- жочками, черных – квадратиками (рис. 4). Рис. 4 Остается вспомнить, что нам надо сделать. Надо поменять местами "встретившихся на одной тропинке коней". Для маневра оставлена клетка 6, на которую может встать один из коней, что- бы пропустить мимо себя других. Теперь решение задачи рожда- ется несложно. Белого коня с клетки 4 передвигаем на клетку 6, пропускаем черных коней с их начальных позиций на клетки 7 и 1. Затем бе- лого коня с клетки 6 перегоняем на клетку 3. Один конь на месте! Отгоняем черных коней на клетки 10 и 2, чтобы освободить для белого коня, стоящего на клетке 5, проход к клетке 6. Когда тот туда проходит, черный конь с клетки 10 беспрепятственно продвигается на клетку 5. Второй конь на месте! Теперь второй черный конь с клетки 2 проходит мимо клетки 6 на клетку 1, освобождая проход для белого коня. Тот немедлен- но пользуется этой ситуацией и продвигается на свое место с клетки 6 на клетку 2. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 6. 6 Последний черный конь становится на требуемую позицию с поля 1 на 4. Кавалерийский маневр завершен! А теперь приведем полный список ходов коней, с помощью которых удалось решить задачу. 1. 4 – 6 2. 2 – 10 3. 10 – 4 4. 4 –1 5. 1 – 7 6. 3 – 9 7. 9 – 8 8. 8 – 2 9. 2 – 10 10. 10 – 4 11. 4 – 1 12. 6 – 4 13. 4 – 10 14. 10 – 2 15. 2 – 8 16. 8 – 9 17. 9 – 3 18. 1 – 4 19. 4 – 10 20. 10 – 2 21. 7 –1 22. 1 – 4 23. 4 –10 24. 5 – 7 25. 7 – 1 26. 1 – 4 27. 4 – 6 28. 10 – 4 29. 4 – 1 30. 1 – 7 31. 7 – 5 32. 2 –10 33. 10 – 4 34. 4 – 1 35. 6 – 4 36. 4 – 10 37. 10 – 2 38. 1 – 4 Более подробный анализ показывает, что полученный алго- ритм, содержащий 38 ходов, является кратчайшим из всех воз- можных! Определения и примеры Итак, в предыдущей части, чтобы успешно решить задачу, нам потребовалось представить её условие наглядно. Для этого мы воспользовались рисунком, на котором отметили возможные Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 7. 7 переходы коней с одной позиции на другую. Подобные рисунки принято называть графами. Наглядное представление о графе можно получить, если представить себе некоторое множество точек плоскости X, назы- ваемых вершинами, и множество отрезков U, соединяющих все или некоторые из вершин. Если при этом рассматриваемые от- резки являются направленными, то они называются дугами, а ес- ли ненаправленными, то ребрами. Дуги используются для обо- значения несимметричных отношений между вершинами, напри- мер отношение "отец – сын", или возможных переходов от одной вершины к другой, например если вершины изображают шахмат- ные позиции, то иногда из одной в другую можно перейти, а на- оборот нельзя (ход пешкой или рокировка). Ребра же изображают симметричные отношения между вершинами, например, если вершины – люди, то наличие ребра между вершинами может оз- начать, что люди знакомы друг с другом. Принято при изображе- нии графов на дугах рисовать стрелку, идущую из начальной вершины в конечную. Итак, что же такое граф? Постараемся дать более формальное определение графа и его компонентов, а также привести приме- ры. Математически граф G можно определить как пару множеств Х и U: G = (Х,U), где X – конечное множество, называемое мно- жеством вершин, а U – некоторое множество пар вершин их X. На рис. 5 изображен граф, вершинами которого являются точки а, b, с, d, е, g, h, а дугами – отрезки (а, а), (с, b), (с, d), (с, е), (d, с), (d, d), (е, d), (g, h). Примерами графов являются отношения отцовства и материнства на множестве людей, карта дорог на ме- стности, схема соединений электрических приборов, отношения превосходства одних участников турнира над другими, и т.п. Введем некоторые понятия и определения, служащие для описания частей графов и их различных видов. Подграфом GA графа G = (X, Г) называется граф, в который входит лишь часть вершин графа G, образующих множество А, вместе с некоторыми дугами, соединяющими эти вершины, на- пример очерченная пунктиром область на рис. 5. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 8. 8 Рис. 5. Граф и подграф Другими важными понятиями являются понятия пути и кон- тура. Ранее было дано определение дуги как направленного от- резка, соединяющего две вершины. Дуга, соединяющая вершины а и b и направленная от а к b, обозначается u = (а, b). Путем в графе G называют такую последовательность дуг m = (Ui, ...,Uk), в которой конец каждой предыдущей дуги совпа- дает с началом следующей. Путь m, последовательными верши- нами которого являются вершины а, b, ..., m, обозначается через m = (a, b, ..., m). Длиной пути m = (u1, ..., ur) называют число l(m) = k, равное числу дуг, составляющих путь m. Иногда каждой дуге Ui припи- сывают некоторое число l(ui), называемое длиной дуги. Тогда длина пути определяется как сумма длин дуг, составляющих путь Путь, в котором никакая дуга не встречается дважды, назы- вается простым. Путь, в котором никакая вершина не встречает- ся дважды, называется элементарным. Контур - это конечный путь m = (Xi,...,Xk), у которого на- чальная вершина Xi совпадает с конечной Xk. При этом контур на- зывается элементарным, если все его вершины различны (за ис- ключением начальной и конечной, которые совпадают). Контур единичной длины, образованный дугой вида (а, а), называется петлей. Так, на рис. 5 (е, d, с, b) – путь, (с, е, d, с) – контур, (d, d) - петля. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 9. 9 Рис. 6. Неориентированный граф Иногда граф рассматривают без учета ориентации дуг, тогда его называют неориентированным графом. Для неориентирован- ного графа понятие "дуга", "путь" и "контур" заменяются поня- тиями "ребро", "цепь", "цикл". Ребро - это отрезок, соединяющий две вершины. Цепь - последовательность ребер. Цикл - цепь, у которой начальная и конечная вершины совпадают. На рис. 6 приведен пример неориентированного графа, у ко- торого вершины обозначены цифрами, а ребра - буквами латин- ского алфавита. Приведем еще несколько определений, служащих для ха- рактеристики неориентированных графов. Степенью вершины, х, обозначаемой deg(x) или dx, называ- ют число ребер, инцидентных вершине х. Так, для графа на рис. 3 имеем: deg(b) = 2, deg(c) = 2, deg(a) = 3, deg(e) = 0. Если deg(x) = 1, то вершину х называют висячей (вершина 4), если deg(x) = 0, то вершину называют изолированной (вершина 5). Нетрудно заметить, что сумма степеней всех вершин гра- фа – четное число. Доказательство следует из того, что каждое ребро добавляет единицу к степени каждой из двух вершин, которые оно соединя- ет, т. е. добавляет 2 к сумме степеней уже имеющихся вершин. Следствие. В каждом графе число вершин нечетной степени четно. Для неориентированного графа понятия "подграф" и "час- тичный граф" аналогичны соответствующим понятиям для ори- ентированного графа. С понятием неориентированного графа связана важная ха- рактеристика, называемая связностью графа. Говорят, что граф Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 10. 10 связен, если любые две его вершины можно соединить цепью. Если граф G не связен, то его можно разбить на такие подграфы Gi, что все вершины в каждом подграфе связны, а вершины из различных подграфов не связны. Такие подграфы G, называют компонентами связности графа G. Если из графа на рис. 6 исключить изолированную вершину 5, то полученный граф будет связным. Граф на рис. 7 не связен и имеет две компоненты связности, его можно превратить в связ- ный, добавив ребро (мост), соединяющее вершины 3 и 5 (штри- ховая линия). Удаление моста превращает связный граф в не- связный. Рис. 7. Мост в графе Для того чтобы определить связность ориентированного графа, не нужно обращать внимание на ориентацию дуг. Граф, изображенный на рис. 5, несвязный. Однако его подграф, со- стоящий из вершин a, с, d, е, является связным. Для ориентиро- ванного графа существует понятие сильной связности. Граф сильно связен, если для любых двух вершин (х и у) существует путь, идущий из х в у. Представления графов в компьютере Описать неориентированный граф G можно путем задания пары множеств (X, U), где Х – множество вершин; U – множество ребер. Однако более удобным, особенно в случае представления графа в компьютере, является описание неориентированного графа с помощью матрицы смежности или инциденции, которые строятся аналогично соответствующим матрицам для ориентиро- ванных графов с той разницей, что не делается различия между заходящей в вершину и исходящей из нее дугами. При этом вер- Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 11. 11 шины x и у называют смежными, если существует соединяющее их ребро, а само это ребро называется инцидентным вершинам х и у. Для графа рис. 6 матрицы смежности и инциденции имеют вид: Матрица смежности: Вершины Вершины 1 2 3 4 5 1 0 1 1 1 0 2 1 0 1 0 0 3 1 1 0 0 0 4 1 0 0 0 0 5 0 0 0 0 0 Матрица инциденции: Ребра Вершины 1 2 3 4 5 a 1 1 0 0 0 b 0 1 1 0 0 c 1 0 1 0 0 d 1 0 0 1 0 Использование матриц смежности или инцидентности удоб- но далеко не всегда. Представим, например, граф железных дорог России, где вершинами являются отдельные станции, а ребрами – участки дороги, соединяющие соответствующие эти станции. Яс- но, что в таком графе много тысяч вершин, а значит, в матрице смежности – несколько миллионов элементов. Причем, в каждой строке этой матрицы количество элементов почти всегда равно двум (через станцию почти вседа проходит только один путь, т.е. она соединена только с двумя соседними станциями). Таким об- Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 12. 12 разом, почти все элементы матрицы смежности равны нулю, и значит, матрица содержит крайне мало информации. При этом она занимает много места, и работать с ней неудобно. Гораздо экономнее представлять дуги в виде списка, но при этом появляется еще одна неприятность – очень трудно становит- ся определить, какие дуги выходят из данной вершины, а такая информация в графе, как правило, является главной. Чтобы сохранить возможность быстрого определения множе- ства дуг, исходящих из данной вершины, можно поступать сле- дующим образом. Рассмотрим сначала работу с ориентирован- ными графами, а затем распространим результат и на неориенти- рованные графы. Во-первых, список дуг отсортируем по первой вершине. Сна- чала в таком отсортированном списке будут следовать дуги, ис- ходящие из первой вершины, затем – из второй, и т.д. Искать нужные дуги, конечно, станет легче, но можно пойти и дальше. Заведем вспомогательный массив, состоящий из n элементов, в котором i-ый элемент означает, с какого места в списке дуг начи- наются дуги, выходящие их i-ой вершины. Назовем новый массив справочным. Таким образом, список дуг и соответствующий справочный массив для графа, изображенного на рис. 6, будут выглядеть сле- дующим образом: Список дуг: 1. (1, 2) 2. (1, 3) 3. (1, 4) 4. (2, 1) 5. (2, 3) 6. (3, 1) 7. (3, 2) 8. (4, 1) Справочный массив: 1. 1 2. 4 3. 6 4. 8 Заметим, что при таком представлении становится ненужным хранить в списке дуг информацию о первой вершине! Поэтому список дуг с оглавлением может выглядеть сле- дующим образом: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 13. 13 Список дуг: 1. 2 2. 3 3. 4 4. 1 5. 3 6. 1 7. 2 8. 1 Справочный массив: 1. 1 2. 4 3. 6 4. 8 Ориентированные графы представляются в виде матриц смежности и инциденции аналогичным образом. Отличие в том, что требуется разным образом отмечать начало и конец дуги. К примеру, если из i-й вершины в j-ю идет дуга, то на пересечении i-й строки и j-го столбца матрицы смежности будет стоять 1, но это не означает, что в симметричной относительно главной диа- гонали (на пересечении j-й строки и i-го столбца) ячейке матрицы смежности тоже будет стоять единица (никто не гарантирует, что из j-й вершины в i-ю тоже идет дуга). К примеру, для следующего графа матрица смежности будет выглядеть так: Вершины Вершины 1 2 3 4 1 0 1 0 1 2 1 0 0 0 3 0 1 0 1 4 0 0 0 0 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 14. 14 Матрица инцидентности строится по уже знакомой схеме – перечисляются дуги и отмечается, какие вершины какими дугами связаны. Если дуга f идет от i-й вершины к j-й, то в соответст- вующей данной дуге строке в i-м столбце поставим –1, а в j-м столбце поставим 1. В незаполненные ячейки вписываются нули. Для рассмотренного выше ориентированного графа матрица ин- цидентности имеет следующий вид: Ребра Вершины 1 2 3 4 a –1 1 0 0 b 1 –1 0 0 c 0 1 –1 0 d –1 0 0 1 e 0 0 –1 1 Аналогично строится список дуг (вместо списка ребер), а также список дуг с оглавлением. При этом необходимо помнить, то дуги имеют направление, и наличие в списке, к примеру, дуги (2, 5) не влечет наличия дуги (5, 2). В оглавлении приводятся ука- затели на позицию в списке дуг, начиная с которой перечисляют- ся дуги, исходящие из конкретных вершин. Алгоритмы нахождения путей в графе Чаще всего при работе с графами требуется находить в них различные пути. Если граф представляет схему дорог, то эта за- дача совершенно естественна. Но даже граф не является схемой дорог, то и тогда пути могут иметь важное значение. В качестве примера можно привести граф состояний шахматной партии, в котором путь может означать способ достижения выигрыша. Существуют разные алгоритмы отыскания путей в графе. Эти алгоритмы ориентированы на конкретные задачи. Например, если требуется просто установить наличие или отсутствие путей меж- ду вершинами (связность графа), достаточно использовать волно- вой алгоритм. Если же требуется искать путь с какими-то свойст- Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 15. 15 вами, например самый короткий, то чаще используют алгоритмы Дейкстры или Флойда. Поиск в графе Одной из наиболее важных задач на графах является задача поиска. В вершинах графа можно хранить некоторые значения, среди которых можно осуществлять поиск удовлетворяющих ус- ловию элементов. Также иногда необходимо решать задачу обхо- да графа, то есть перечисления всех его вершин (или значений, записанных в этих вершинах) ровно по одному разу. Мы рас- смотрим два способа обхода (поиска) вершин в графе – поиск в глубину и поиск в ширину. Поиск в глубину Поиск (обход) начинаем с некоторой вершины. Сначала про- сматриваем первую вершину (под просмотром можно понимать вывод номера вершины на экран или в файл, анализ содержаще- гося в вершине значения или какое-либо другое действие) – пусть это вершина u. Потом просматриваем смежную с ней вершину (v). Далее посматриваем вершину, смежную с v (вершина w), и т. д. На каждом шаге после рассмотрения очередной вершины (t) просматриваем произвольную из не просмотренных ранее вер- шин, смежных с текущей вершиной t. Если же у вершины t нет смежных вершин, которые мы еще не рассматривали, то возвра- щаемся на предыдущую вершину и ищем непросмотренные смежные (уже с ней) вершины. Если и у этой вершины нет "сосе- дей", не просмотренных ранее, то возвращаемся еще на один шаг назад, и т. д. Процесс заканчиваем тогда, когда на одном из шагов алгоритма требуется сделать шаг назад относительно вершины, с которой мы начинали просмотр. При организации такого просмотра можно использовать стек (для хранения номеров просматриваемых вершин) и массив (для пометок просмотренных вершин). Считаем, что уже определены операции помещения элемента в стек, выборки элемента с вер- шины стека, просмотра элемента на вершине стека, проверки, яв- ляется ли стек пустым. В массив M будем записывать 1 в k-ю ячейку, если k-я вершина просмотрена, и 0 – в противном случае. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 16. 16 В начале работы стек пуст, а массив M заполнен нулями. Пусть C – матрица смежности графа (C[i,j] = 1, если есть ребро (i,j) и 0 – в противном случае). Обход графа начнем с вершины с номером 1. Алгоритм опишем следующим образом: Push(1); {поместили в стек номер 1-й вершины,...} Просмотреть(1); {посмотрели ее...} M[1]:=1; {и пометили как просмотренную} while not Empty do {пока есть вершины, подлежащие обработке...} begin v:=Top; {номер текущей вершины берем с вершины стека} s:=0; {будем записывать в s номер очередной вершины} for k:=1 to N do if M[k]=0 and C[v,k]=1 {нашли непросмотренную вершину,} then begin {смежную с v} s:=k; {запоминаем ее номер} break; {выходим из цикла} end; if s<>0 then {если очередная вершина была найдена,...} begin Просмотреть(s); {просматриваем ее} M[s]:=1; {помечаем ее как просмотренную} Push(s); {и помещаем ее в стек} end else s:=Pop; {удаляем текущую вершину из стека} end; Алгоритм поиска в глубину можно записать и в рекурсивной форме. В этом случае определим рекурсивную процедуру Search(k), где k – номер вершины, начиная с которой мы осуще- ствляем поиск в глубину: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 17. 17 procedure Search(k: integer); begin Просмотреть(k); M[k]:=1; for t:=1 to N do if (C[k,t]=1) and (M[t]=0) then Search(t); end; Таким образом, при данном способе поиска граф просматри- ваем в глубину так, как это возможно, а когда дальнейший про- смотр невозможен, возвращаемся немного назад и пытаемся про- должить просмотр уже по несколько другому пути. Поиск в ширину Если при поиске в глубину мы последовательно просматри- вали вершины графа до тех пор, пока это возможно, то при поис- ке в ширину вначале будут просмотрены вершины, смежные с начальной, потом – вершины, смежные с теми, которые смежны с начальной, и т. д., пока не будут просмотрены все вершины гра- фа. Иначе говоря, раньше будут просмотрены те вершины, кото- рые находятся на меньшем расстоянии от начальной вершины (под расстоянием между вершинами понимается длина кратчай- шего пути между ними). Подлежащие рассмотрению вершины удобно хранить в оче- реди. В начале работы в очередь поместим номер начальной вер- шины. Затем в очередь добавляем номера вершин, смежных с на- чальной, а номер самой начальной вершины из очереди удалим. Потом берем из очереди номер следующей вершины, помещаем в очередь номера смежных с ней вершин, а саму вершину удаляем, и т. д. Понятно, что при таком способе просмотра вершины, ко- торые расположены ближе к начальной, будут рассмотрены раньше, чем те, которые находятся от начальной вершины на большем расстоянии (действительно, ведь они раньше помещены в очередь просмотра вершин). Ниже приведем алгоритм (при этом предполагаем, что опре- делены операции работы с очередью – добавления элемента (In- Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 18. 18 sert), удаления элемента (Remove), проверки, является ли очередь пустой (Empty)). procedure Search2(k: integer); begin Insert(k); {помещаем в очередь номер начальной вершины} M[k]:=1; while not Empty do {пока в очереди есть подлежащие обработке вершины,} begin {просматриваем их} v:=Remove; {берем очередную вершину из очереди,} Просмотреть(v); {просматриваем ее} for t:=1 to N do if (C[v,t]=1) and (M[t]=0) {все смежные с ней вершины,} then begin {которые не были еще просмотрены,} Insert(t); {добавляем в} M[t]:=1; {очередь просмотра} end; end; end; С подобного рода алгоритмами мы встречались и ранее: вспомните алгоритм обхода лабиринта, где мы помечали про- смотренные клетки. При этом число, которое записано в клетке лабиринта, означало длину кратчайшего маршрута от начальной клетки до данной. Аналогичное утверждение верно и для графа. Просмотрен- ные вершины мы пока что помечали единицами, остальные – ну- лями. Способ пометки можно несколько модифицировать: будем помечать вершины, которые еще не просмотрели, числами –1, а просмотренные вершины – отличными от –1 числами. При этом начальную вершину можно пометить нулем, а остальные поме- чать следующим способом: если вершина помечена числом k, то смежные с ней вершины (которые мы еще не просмотрели) будем Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 19. 19 помечать числом k+1 и добавлять в очередь просмотра. Алгоритм модифицируется следующим образом: procedure Search3(k: integer); begin for t:=1 to N do M[k]:=-1; Insert(k); {помещаем в очередь номер начальной вершины} M[k]:=0; {помечаем ее нулем} while not Empty do {пока в очереди есть подлежащие обработке вершины} begin {просматриваем их} v:=Remove; {берем очередную вершину из очереди} Просмотреть(v); {просматриваем ее} for t:=1 to N do if (C[v,t]=1) and (M[t]=-1) {все смежные с ней вершины,} then begin {которые не были еще просмотрены,} Insert(t); {добавляем в очередь просмотра} M[t]:=M[v]+1; {и помечаем} end; end; end; В результате работы этого алгоритма пометки будут иметь следующий смысл: если вершина помечена числом k, то расстоя- ние (длина кратчайшего пути) от начальной вершины до данной равно k. Если граф был несвязным, то некоторые вершины так и останутся помеченными числом –1. Поэтому данный алгоритм (да и первый алгоритм поиска в ширину тоже) можно использо- вать для проверки связности графа. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 20. 20 Поиск кратчайшего пути между двумя вершинами Постановка задачи Решим следующую задачу: имеется несколько городов, неко- торые из которых соединены дорогами, причем длины дорог из- вестны. Требуется найти длину кратчайшего пути между двумя выбранными городами. Конечно, можно было бы предложить перебрать все возмож- ные пути между выбранными городами, после чего выбрать из них кратчайший. Но сразу ясно, что такой способ хорошим никак назвать нельзя. Во-первых, сложность состоит в самом переборе путей, а во-вторых, не стоит рассчитывать на оптимальность та- кого переборного алгоритма. Поэтому для решения этой задачи мы будем использовать более эффективные алгоритмы. Для начала сформулируем данную задачу на языке теории графов. Итак, у нас есть связный граф с N вершинами (то есть, из любой вершины можно попасть в любую другую). Каждое ребро имеет определенный вес. Веса удобно записывать в матрицу смежности – двумерный массив C (NxN), при этом элемент C[i,j] – вес ребра, соединяющего вершины с номерами i и j. Граф, в котором ребрам приписаны веса, называется взве- шенным. Также удобно считать, что если две вершины не соединены ребром, то вес ребра между этими вершинами равен бесконечно- сти. Иначе говоря, добавляем отсутствующие ребра, дополняя граф до полного графа (в котором все вершины попарно соедине- ны), при этом добавляемые ребра (те, которых не было в исход- ном графе) получают бесконечный вес. В качестве "бесконечно- сти" можно использовать очень большое целое число (например, такое число, которое больше суммы весов всех ребер в исходном графе). Петлям (ребрам, идущим из вершины в саму эту верши- ну) можно приписать вес 0. Так как между отмеченными вершинами существует путь, то при добавлении таких фиктивных ребер (с бесконечными весами) мы "не испортим" результат. Действительно: кратчайший путь не может содержать ребро бесконечного веса, так как существует Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 21. 21 путь короче (просто произвольный путь между отмеченными вершинами по имеющимся в исходном графе ребрам). Весом (длиной) пути будем называть сумму весов всех вхо- дящих в путь ребер. Требуется найти длину кратчайшего пути между двумя заданными вершинами графа. Длину кратчайшего пути между вершинами будем также называть расстоянием. Для решения задачи нахождения длины кратчайшего пути между вершинами обычно используют алгоритмы Дейкстры и Форда – Беллмана. Алгоритм Дейкстры Рассматриваемый алгоритм (алгоритм Дейкстры) решает бо- лее общую задачу: пусть в графе выделена некоторая вершина. Тогда найдем кратчайшие расстояния от данной вершины до всех остальных вершин графа. Если нам нужно найти кратчайшее рас- стояние между двумя заданными вершинами, то можно взять первую вершину, применить для графа с данной выделенной вершиной алгоритм Дейкстры, после чего выбрать из получен- ных данных расстояние от первой вершины до второй. Очевидна некоторая избыточность: возможно, нам и не нуж- но находить расстояния от данной вершины до всех остальных, а интересует путь только лишь между двумя заданными вершина- ми. Однако эффективных алгоритмов, которые находят лишь нужный нам путь (и не решают указанную выше общую задачу) пока не известно. Пусть выделена некоторая вершина v. В ходе работы алго- ритма Дейкстры будем заполнять массив D кратчайших расстоя- ний от вершины v до всех остальных вершин в графе. В итоге для каждого значения k от 1 до N в элементе D[k] будет содержаться кратчайшее расстояние между вершинами v и k. В ходе работы алгоритма также будем помечать некоторые вершины. В начале работы алгоритма помечена только начальная вершина (первая), в конце работы оказываются помеченными все вершины. При этом на каждом шаге работы алгоритма для каж- дой помеченной вершины хранится длина самого короткого пути между первой вершиной и данной, причем известно, что путь минимальной длины проходит только через помеченные города. А для каждой непомеченной вершины хранится наименьшая Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 22. 22 длина среди всех путей от первой вершины до данной, в которых в качестве промежуточных используются помеченные города. Иначе говоря, хранимое для непомеченной вершины число пока- зывает, какое наименьшее расстояние нужно преодолеть от вер- шины 1 до данной, если в качестве промежуточных можно ис- пользовать только помеченные вершины. Все эти числа можно хранить в массиве D. Данные хранимые величины будем называть оценками длин кратчайших путей. Оценки кратчайших путей для помеченных вершин являются точными, а для непомеченных требуют корректировки при каж- дой пометке очередной вершины. На каждом шаге алгоритма будем добавлять к множеству помеченных вершин еще одну вершину, а для непомеченных вершин будем корректировать оценки кратчайших путей. Выбор очередной вершины осуществляется следующим образом: рас- смотрим все непомеченные вершины, выберем из них ту, для ко- торой оценка длины кратчайшего пути минимальна (пусть это вершина z), и пометим ее. Легко убедиться в том, что данная оценка кратчайшего пути до вершины z является точной. Дейст- вительно, если рассмотреть путь, содержащий какую-нибудь не- помеченную вершину w, то уже до вершины w путь будет длин- нее, чем рассматриваемая оценка кратчайшего пути, а ведь от w нужно дойти до вершины z. После того как вершина z будет помечена, требуется скор- ректировать оценки кратчайших расстояний до непомеченных вершин. Сделать это не очень сложно: кратчайшее расстояние до непомеченной вершины может содержать вершину z, а может и не содержать ее. Длина кратчайшего пути, проходящего за все помеченные вершины, кроме z, уже известны. А среди остальных путей с промежуточными помеченными вершинами можно рас- смотреть лишь те, в которых вершина z (последняя помеченная) является последней промежуточной вершиной. Данную операцию повторяем до тех пор, пока не будут по- мечены все вершины. Учитывая все сказанное выше, алгоритм Дейкстры поиска длины кратчайшего пути от вершины v до остальных вершин можно описать следующим образом: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 23. 23 Шаг 1: Для k от 1 до N: D[k]:=C[v,k]; {начальные оценки длины путей} M:=[1..N]-[v]; {множество непомеченных вершин} Пока M не пусто выполнять шаг 2. Шаг 2: w – непомеченная вершина оценка длины пути мини- мальна; {D[w] минимальна среди всех D[k] для непоме- ченных k} M := M-[w]; {исключаем w из множества непомечен- ных вершин} Для всех k из множества M: D[k] := min{D[k],D[w]+C[w,k]}; После заполнения массива D достаточно выбрать из него кратчайшее расстояние от вершины v до любой другой вершины. Покажем работу алгоритма Дейкстры на примере. Рассмот- рим следующий граф: Рис. 8. Взвешенный граф Матрица весов C для данного графа выглядит следующим образом: 0 7 5 ∞ ∞ ∞ ∞ ∞ 7 0 9 4 ∞ 6 ∞ ∞ 5 9 0 7 8 ∞ ∞ ∞ ∞ 4 7 0 6 ∞ 9 ∞ ∞ ∞ 8 6 0 ∞ 8 ∞ ∞ 6 ∞ ∞ ∞ 0 11 7 ∞ ∞ ∞ 9 8 11 0 6 ∞ ∞ ∞ ∞ ∞ 7 6 0 Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 24. 24 Будем искать расстояния от вершины с номером 1 до всех остальных вершин. В начале работы алгоритма массив D (массив оценок кратчайших путей) заполняем просто длинами ребер от первой вершины до каждой из оставшихся вершин: D = [0, 7, 5, ∞, ∞, ∞, ∞, ∞] Помеченной является пока только первая вершина. Заметим, что оценка расстояния до нее является точной: она равна нулю и меньше быть не может. Теперь начинаем помечать и остальные вершины. Среди всех непомеченных вершин (а ими пока являются все вершины, кроме первой) выбираем ту, для которой оценка длины кратчайшего пу- ти минимальна (фактически, выбираем минимальный из элемен- тов массива D, соответствующий непомеченным вершинам). Такой является вершина с номером 3 (а соответствующая оценка равна 5). Помечаем эту вершину и начинаем пересчиты- вать оценки расстояний. Оценка либо останется прежней (пока кратчайший путь проходит через те же вершины, что и до добав- ления новой вершины в список помеченных), либо изменилась (если кратчайший путь проходит через вновь добавленную поме- ченную вершину). Для этого (в соответствии с алгоритмом) для всех k, отличных от 1 и 3, в качестве элемента D[k] выбирается минимум из D[k] (прежнее значение) и D[2]+C[3,k] (новый крат- чайший путь проходит через добавленную вершину 3). Итак, оценка расстояния до вершины 2 не изменилась (по- прежнему короче путь напрямую от вершины 1, нежели "с пере- садкой" в помеченной вершине 2). Не изменятся оценки длины кратчайшего пути и до вершин 6, 7, 8: он равен "бесконечности" как без использования промежуточной вершины 3, так и с ис- пользованием ее в качестве "перевалочного пункта". Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 25. 25 А вот оценки расстояний до вершин 4 и 5 изменятся. Дейст- вительно, длина прямого пути от вершины 1 до вершины 4 была равена "бесконечности", а теперь проще будет добраться до нее через вершину 3 и оценка кратчайшего пути равна 5 + 7 = 12. Иначе говоря, D[4] := min{D[4], D[3]+C[3,4]} = min{∞, 5+7} = min{∞,12} = 12. Аналогично меняется оценка длины кратчайшего пути до вершины 5 – она теперь равна 13 (путь через вершину 3). После пересчета оценок расстояний (длин кратчайших пу- тей) граф и массив D выглядят так: D = [0, 7, 5, 12, 13, ∞, ∞, ∞] Снова ищем вершину для того, чтобы ее пометить. Для этого в массиве D выбираем наименьший из тех элементов, которые не соответствуют помеченным вершинам (это все элементы, кроме первого и третьего). Таким элементом будет второй: для него оценка расстояния равна 7. Помечаем его и пересчитываем оцен- ки расстояний. Для вершин 7 и 8 они не изменятся (как были равны беско- нечности, так и будут). До вершины 5 по-прежнему короче путь через вершину 3, нежели через добавленную вершину 2. А оцен- ки расстояний до вершин 4 и 6 необходимо скорректировать: до вершины 4 короче оказывается путь через вершину 2 (был равен 12, стал равен 11), а до вершины 6 оценка расстояния была равна бесконечности, а теперь в нее можно попасть через вершину 2 (и соответствующее расстояние равно 13). После этого имеем сле- дующий граф матрицу оценок: D = [0, 7, 5, 11, 13, 13, ∞, ∞] Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 26. 26 Продолжаем помечать вершины. Из массива D выбираем элемент с номером 4 (для соответствующей вершины оценка рас- стояния оказывается наименьшей среди непомеченных). Помеча- ем ее, выполняем пересчет оценок расстояний: D = [0, 7, 5, 11, 13, 13, 20, 21] Помечать вершины продолжаем до тех пор, пока все они не окажутся помеченными. Стоит обратить внимание на то, что оценки для помеченных вершин являются точными и не меняют- ся при пометке новых вершин. Итак, на следующем шаге можно пометить либо вершину 5, либо вершину 6 (пятый и шестой элементы массива D одинаковы и равны 13, поэтому можно выбрать любую из данных вершин). Пометим вершину 5. С учетом того, что была помечена новая вершина, осуществляем пересчет оценок расстояний: D = [0, 7, 5, 11, 13, 13, 20, 21] Заметим, что при этом массив D не изменился. Это означает, что пути, проходящие через вершину 5 до непомеченных вершин, не короче рассмотренных ранее путей, которые эту вершину не содержат. Далее осталось выбрать минимальный из элементов массива D с номерами 6, 7, 8 (они соответствуют непомеченным вершинам). Таким является элемент с номером 6, соответственно шестую вершину мы и помечаем. При пересчете оценок расстоя- ний они меняется только оценка длины пути до вершины 8 (те- перь короче будет путь через вершину 6), остальные остаются без изменений: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 27. 27 D = [0, 7, 5, 11, 13, 13, 20, 20] Осталось две непомеченные вершины: 7 и 8. Соответст- вующие элементы массива оценок D равны, поэтому можно по- метить любую из них. Пометим вершину 7. Это не изменит мас- сива оценок расстояний: D = [0, 7, 5, 11, 13, 13, 20, 20] Теперь осталась только вершина 8, которую нужно просто пометить. Так как непомеченных вершин после этого не остается, то и пересчитывать оценки расстояний не нужно. В результате получаем следующий граф и массив оценок расстояний (D): D = [0, 7, 5, 11, 13, 13, 20, 20] Теперь мы можем определить длину кратчайшего пути от вершины 1 до любой другой вершины. Например, длина крат- чайшего пути от вершины 1 до вершины 7 равна 20 (седьмой элемент массива D). Однако это не дает нам самого пути, а лишь показывает его длину. Оценим трудоемкость алгоритма. Работу алгоритма можно условно разделить на N шагов, на каждом из которых мы помеча- ем вершину. При пометке вершины мы пересчитываем оценки Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 28. 28 расстояний до вершин, что требует порядка N действий на каж- дом шаге. Итого получается порядка N 2 действий. Таким обра- зом, можем сделать вывод, что порядок роста трудоемкости со- ставляет N 2. Вообще говоря, ожидать меньшей трудоемкости не представ- ляется возможным. Действительно, при построении кратчайшего пути мы должны учитывать все длины (веса) ребер, что требует просмотра матрицы весов размера NxN, что требует уже порядка N 2 действий. Теперь рассмотрим несколько другую ситуацию: пусть на дорогах между городами установлено одностороннее движение. В принципе, между двумя городами могут существовать и пря- мой, и обратный путь, но ничто не мешает им иметь разную дли- ну (иначе говоря, длина дороги из города v в город w может быть не равна длине дороги из w в v). В этом случае в матрице весов элемент C[i,j] может быть не равен элементу C[j,i] (в случае дву- стороннего движения эти элементы были равны, то есть матрица была симметричной относительно главной диагонали). Требуется найти длины кратчайших путей от выделенной вершины до всех остальных вершин. Если нет ребра из вершины v до вершины w (ориентирован- ное ребро чаще называют дугой), то удобно приписывать ему вес, равный бесконечности. Понятно, что для решения данной задачи можно использо- вать тот же самый алгоритм Дейкстры. Обратите внимание, что при описании алгоритма Дейкстры мы нигде не опирались на симметричность путей (то есть на равенство C[i,j] = C[j,i]), по- этому алгоритм будет давать решение и в случае однонаправлен- ных (ориентированных) дорог. Граф, в котором каждое из ребер имеет направление, называ- ется ориентированным. Если каждому из ориентированных ребер (каждой из дуг) приписан вес, то такой граф называется взвешен- ным ориентированным графом. Итак, алгоритм Дейкстры предназначен для поиска длины кратчайшего пути от выделенной вершины до всех остальных как в неориентированном ("обычном") графе, так и в ориентирован- ном, в том случае, если веса ребер (дуг) положительны. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 29. 29 Алгоритм Форда – Беллмана Рассмотренный выше алгоритм (алгоритм Дейкстры) исполь- зовал достаточно простую идею: оценками расстояний были дли- ны кратчайших путей с использованием в качестве промежуточ- ных вершин только помеченных, а набор помеченных вершин по- стоянно расширялся до тех пор, пока не охватывал все вершины графа (при этом все оценки расстояний оказывались точными). Следующий алгоритм (алгоритм Форда – Беллмана) будет также основан на достаточно простой идее: будем последова- тельно находить длины кратчайших путей от выделенной верши- ны до всех остальных вершин с количеством промежуточных вершин не более k (последовательно для всех k от 0 до N–2). То- гда, когда будет рассмотрен случай k = N–2, мы получим точные оценки. Действительно, кратчайший путь не может содержать более N–1 ребер (он соответствует случаю N–2 пересадок), иначе он содержит цикл, а поэтому не будет являться кратчайшим. Ключевым моментом является переход от наибольшего ко- личества промежуточных вершин k к количеству k+1. Сделаем обозначение: пусть D[w,k] – длина кратчайшего пути от выде- ленной вершины v до вершины w с использованием не более k пересадок (промежуточных вершин). Тогда каким образом можно добраться по кратчайшему пути от v до w с использованием не более k+1 пересадок? Очевидно, что достаточно рассмотреть имеющийся путь от v до w с использованием не более k переса- док, а также все пути, состоящие из пути от v до вершины i (i от 1 до N) с добавлением ребра (i, w), после чего выбрать из рассмот- ренных путей самый короткий. Итак, имеем: D[w,k+1] = min{D[w,k], D[i,k]+C[i,w] для всех i от 1 до N}. Пересчет оценок расстояний продолжаем, пока k не примет значение N–2. После этого оценки окажутся точными. Алгоритм можно описать так: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 30. 30 Шаг 1: k:=0; Для всех i от 1 до N: D[i,0]:=C[v,i] {первоначальные оценки расстояний – длины путей без пересадок} Пока k<N–1 выполнять шаг 2; Шаг 2: Для всех w от 1 до N выполняем следующие действия: D[w,k+1]:=min{D[w,k], D[i,k]+C[i,w] для всех i от 1 до N}; {выполняем пересчет оценок расстояний} k:=k+1; {увеличиваем k на 1} Понятно, что аналогичный алгоритм можно применить и для нахождения длины кратчайшего пути во взвешенном ориентиро- ванном графе. Итак, алгоритм Форда – Беллмана также основан на доста- точно простой идее. Однако (в отличие от алгоритма Дейкстры) этот алгоритма имеет достаточно высокую трудоемкость: она со- ставляет порядка N 3 (где N – количество вершин в графе), по- этому проигрывает по трудоемкости алгоритму Дейкстры. Поиск длин кратчайших путей между всеми вершинами. Алгоритм Флойда Рассмотренные выше алгоритмы были предназначены для поиска длины кратчайшего пути между двумя выделенными вершинами. В качестве "побочного продукта" они давали длины кратчайших путей от выделенной вершины до всех остальных вершин графа. Решим еще более общую задачу: найдем длины кратчайших путей между каждой парой вершин в графе (без разницы, являет- ся он ориентированным или нет). В принципе, можно было бы, последовательно выбирая в качестве начальной все вершины графа, N раз применить алгоритм Дейкстры (добившись оценки трудоемкости порядка N3 ). Но на практике обычно используют Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 31. 31 другой алгоритм с тем же порядком роста трудоемкости – алго- ритм Флойда. Данный алгоритм также основан на идее последовательного пересчета оценок расстояний. Обозначим через D[i,j,k] длину кратчайшего пути из вершины i в вершину j с использованием промежуточных вершин из множества [1,…,k] (то есть, с номе- рами от 1 до k). Переход от D[i,j,k] к D[i,j,k+1] осуществляется следующим образом: кратчайший путь с промежуточными вер- шинами 1, …, k+1 может не содержать вершины k (тогда он ра- вен D[i,j,k]), а может содержать, тогда он разбивается на крат- чайший путь от вершины i до вершины с номером k+1 и на крат- чайший путь от вершины k+1 до вершины j. Учитывая сказанное выше, формулу пересчета можно записать так: D[i,j,k+1] = min{ D[i,j,k], D[i,k+1,k]+ D[k+1,j,k]}. Алгоритм можно записать следующим образом: Шаг 1: Для всех i от 1 до N и для всех j от 1 до N выполняем: D[i,j,0] := C[i,j]; {начальные оценки расстояний} Шаг 2: Для всех k от 1 до N выполняем следующие действия: Для всех х i от 1 до N и для всех j от 1 до N выполняем: D[i,j,k+1]=min{D[i,j,k];D[i,k+1,k]+D[k+1,j,k]} В результате работы данного алгоритма длины кратчайших расстояний между вершинами i и j будут находиться в элементах D[i,j,N]. Понятно, что можно оценки все время хранить в одном и том же двумерном массиве D. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 32. 32 Деревья Основные определения Одним из частных случаев графов является дерево. С этим понятием мы уже сталкивались в главе "Структуры данных", ко- гда работали с бинарными деревьями. Действительно, приведен- ную тогда схему можно считать графом, в котором узлы дерева являются вершинами графа, а узел соединяется с потомками реб- рами. При этом от любого узла по таким ребрам можно добраться до любого другого (более формально это означает, что рассмат- риваемый граф является связным), причем единственным спосо- бом. Однако слово "бинарное", очевидно, уже предполагает неко- торое дополнительное условие, накладываемое на дерево. Дадим определение дерева в общем виде. Дерево – это связный граф без циклов. Несложно убедиться в том, что бинарное дерево является деревом и по только что при- веденному определению. Примерами деревьев являются и моле- кулы некоторых химических веществ, например предельных уг- леводородов, при этом атомы являются вершинами, а связи меж- ду ними – ребрами (именно с рассмотрения такого рода графов в середине XIX века и началось активное изучение деревьев и их свойств). Пример дерева приведен на рисунке 1. Рис. 9. Пример дерева Данное выше определение дерева не является единствен- ным. Приведем еще несколько эквивалентных определений (эк- вивалентность в данном случае означает, что из любого приве- денного определения можно получить другое): • Дерево – это связный граф, в котором любые две вер- шины соединены единственным простым путем. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 33. 33 • Дерево – это связный граф, в котором количество ребер на 1 меньше количества вершин. • Дерево – это граф без циклов, в котором количество ребер на 1 меньше количества вершин. • Дерево – это граф без циклов, в котором при соедине- нии любой пары несмежных вершин образуется цикл. И этот список можно продолжать. С другой стороны, приве- денные выше определения можно рассматривать как свойства де- ревьев. Понятно, что дерево можно получить из любого связного графа. Для этого можно выполнить следующие действия: пока граф содержит циклы, выбираем один из них и удаляем в нем од- но из ребер. Например, если есть связная сеть дорог, соединяю- щая несколько городов, то пока эта сеть содержит циклы, мы мо- жем закрывать входящие в циклы дороги (по одной). Понятно, что при этом граф остается связным. Действительно, если произ- вольные две вершины (два города) были соединены путем, то по- сле удаления ребра (дороги) эти вершины все равно оказываются связанными путем: если путь проходил через удаленное ребро, которое входило в цикл, то из одной вершины в другую все равно существует путь "в объезд" удаленного ребра. Полученное дерево, очевидно, будет содержать те же самые вершины, что и исходный граф, а ребра дерева являлись изна- чально ребрами исходного графа. Такого рода дерево называется остовом (или каркасом). Понятно, что остовов в графе может быть несколько. На ри- сунке 10 приведен пример графа (1) и нескольких его остовов (2, 3 и 4): Рис. 10. Граф и его остовы Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 34. 34 В графе с достаточно большим количеством ребер остовов может быть очень и очень много. Одной из задач будет нахожде- ние среди всего множества остовов тех, которые обладают опре- деленным свойством. Решением такого рода задач мы сейчас и займемся. Остов минимального веса Рассмотрим следующую задачу. Пусть есть некоторый набор деревень, между некоторыми из которых проложены грунтовые дороги, образующие связную систему (то есть из любой деревни можно добраться до любой другой, возможно, "транзитом" через какие-то промежуточные деревни). Для того чтобы обеспечить связь между деревнями в межсезонье (когда грунтовые дороги становятся неприспособленными для езды), решено некоторые из грунтовых дорог покрыть асфальтом так, чтобы из любой дерев- ни можно было проехать до любой другой, используя только за- асфальтированные дороги. При этом стоимость асфальтирования разных дорог может быть различной (например, зависеть от дли- ны дороги и особенностей рельефа). Наша задача: построить связную систему асфальтированных дорог с наименьшими рас- ходами. Переведем условие задачи на язык теории графов. Итак, де- ревни можно считать вершинами, а грунтовые дороги между ни- ми – ребрами. Так как из любой деревни можно было проехать до любой другой, то такой граф является связным. Также мы имеем некоторую дополнительную информацию: знаем, сколько стоит асфальтирование каждой из дорог. В этом случае говорят, что каждому ребру приписан определенный вес (а граф называется взвешенным): Рис. 11. Взвешенный граф Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 35. 35 Чаще всего веса ребер заносятся в двумерный массив, кото- рый называется матрицей весов: в ячейку на пересечении i-й строки и j-го столбца записывают вес ребра между i-й и j-й вер- шиной. Иногда для удобства считают, что в графе каждая верши- на соединена с каждой, но вес несуществующих в исходном гра- фе ребер равен бесконечности. Применительно к задаче об ас- фальтировании дорог это можно сформулировать так: постройка асфальтированной дороги между двумя деревнями, не соединен- ными между собой грунтовой дорогой, требует бесконечных (или крайне больших) затрат. Для графа, приведенного на рисунке 3, матрица весов будет иметь следующий вид (символом "∞" обо- значен бесконечный вес ребра): 0 8 6 8 ∞ 8 0 6 ∞ ∞ 6 6 0 5 7 8 ∞ 5 0 10 ∞ ∞ 7 10 0 Рис. 12. Матрица весов Такие "несуществующие" ребра (дороги) с бесконечными ве- сами, как легко заметить, не будут входить в искомую минималь- ную сеть дорог. Действительно, наличие в сети такого ребра авто- матически делает ее общую стоимость бесконечной, но понятно, что мы можем построить сеть асфальтированных дорог с меньши- ми затратами, просто взяв совершенно произвольный остов. Почему же сеть дорог минимальной стоимости мы будем ис- кать именно среди остовов? Ответ достаточно очевиден. Дейст- вительно, полученная сеть дорог должна связывать все деревни друг с другом, поэтому мы должны найти связный граф. Также эта сеть дорог минимальной не должна содержать циклов, иначе мы могли бы выбросить одну из дорог (то есть не асфальтировать одну из грунтовых дорог) в данном цикле и получить сеть дорог меньшей стоимости. Итак, искомая сеть дорог минимальной стоимости действительно должна быть связным графом без цик- лов, то есть деревом. А так как это дерево содержит все вершины (соединяет все деревни), то это остов. Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 36. 36 Таким образом, задачу можно сформулировать следующим образом: в заданном взвешенном графе найти остов минимально- го веса. Рассмотрим два способа решения данной задачи: алго- ритм Прима и алгоритм Краскала. Алгоритм Прима Идея алгоритма достаточно проста. Будем строить остов, по- степенно добавляя по одному ребру. Первым в остов включаем ребро с наименьшим весом (в нашей задаче: асфальтируем ту до- рогу, покрытие которой асфальтом потребует наименьших за- трат). Далее на каждом шаге присоединяем к сети не рассмотрен- ное ранее ребро минимального веса, причем выбираем мини- мальное среди тех ребер, добавление которых к сети не образует цикла. Иначе говоря, на каждом шаге мы имеем дерево, к которому присоединяем ребро (с вершиной) так, чтобы полученная сеть ос- тавалась деревом, причем добавляем наиболее "легкое" из таких ребер. Как добиться того, чтобы при добавлении ребра не образовы- вался цикл? Очевидно, для этого мы должны проводить ребро от уже построенной сети к одной из тех вершин, которые мы еще не рассматривали. Представим себе рабочих, которые асфальтируют дороги по данному алгоритму. В самом начале работы они заасфальтирова- ли дорогу, затраты на покрытие асфальтом которой самые низкие (то есть покрыли асфальтом одну из дорог, затратив на это мини- мум средств), соединив таким образом какие-то две деревни. А дальше они смотрят, какую деревню из тех, до которых еще не достроена сеть асфальтированных дорог, можно было бы присое- динить к сети с наименьшими затратами. Дорога, обладающая данными условиями, покрывается асфальтом, после чего рабочие снова ищут новую деревню, чтобы присоединить к сети, "протя- нув" к ней дорогу. Эту операцию последовательно проделывают до тех пор, пока все деревни не окажутся присоединенными к се- ти асфальтированных дорог. Может возникнуть вполне естественный вопрос: находит ли этот алгоритм действительно остов минимального веса. Да, нахо- Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 37. 37 дит, и это можно строго доказать. Однако на этом мы останавли- ваться не будем. Вместо этого уделим некоторое внимание организации поис- ка нового добавляемого ребра. Действительно, эту операцию приходится проделывать на каждом шаге алгоритма. Добавляе- мое ребро соединяет одну из рассмотренных ранее вершин с од- ной из нерассмотренных. Поэтому кажется вполне естественным ввести два множества: множество рассмотренных вершин (X) и множество нерассмотренных вершин (Y). Перед началом работы алгоритма множество X пусто, а Y содержит все вершины (дей- ствительно, мы ведь еще не рассмотрели ни одну из вершин). На первом шаге (при включении в сеть первого ребра) в множество X включаем две вершины, связанные добавляемым ребром наи- меньшего веса, и, соответственно, исключаем эти две вершины из множества Y. А далее на каждом шаге мы делаем следующее: рассматриваем все ребра, соединяющие вершины множества X с вершинами множества Y, и выбираем из них то, которое имеет меньший вес. Пусть оно соединяет вершину x (из множества X) с вершиной y (из Y). Добавляем ребро (x, y) к сети, вершину y до- бавляем к множеству X и исключаем из множества Y. Так про- должаем делать до тех пор, пока в множестве Y не останется вершин. Множества X и Y можно организовать с помощью списков, массивов или переменных множественного типа. Как же найти ребро минимального веса среди тех, которые соединяют множество X с множеством Y? Для решения этой за- дачи можно рассмотреть те элементы матрицы весов, которые стоят на пересечении строк с номерами из X и столбцов с номе- рами из Y, и найти среди них наименьший. Иначе говоря, ищем наименьший элемент в таблице, получающейся из матрицы весов исходного графа выкидыванием всех строк с номерами, не со- держащимися в X, и столбцов с номерами, не содержащимися в Y. Если такой элемент находится в строке с номером x и столбце с номером y, то ребро (x,y) – искомое. Обобщая изложенное выше, алгоритм Прима можно в общих чертах описать следующим образом: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 38. 38 X – пустое множество; Y – содержит все вершины; Найти в матрице весов наименьший элемент: x = номер соответствующей строки, y = номер столбца; Добавить ребро (x,y) в сеть; Добавить x и y в X; Исключить x и y из Y; while (Y не пусто) do begin Найти в матрице весов наименьший из элементов на пересечении строк с номерами из X и столбцов с но- мерами из Y: x = номер строки, y = номер столбца; Добавить ребро (x,y) в сеть; Добавить y в X; Исключить y из Y; end; Проследим ход выполнения алгоритма Прима на примере. Пусть имеется сеть дорог следующего вида: Вначале множество X пусто, множество Y содержит все вер- шины: X = {}; Y = {1, 2, 3, 4, 5, 6, 7}. Начинаем построения остова минимального веса с выбора самого "легкого" ребра. Этим свойством обладает ребро, соеди- няющее вершины 1 и 5 (его вес равен 5). Добавляем его к остову, а вершины 1 и 5 добавляем к множеству X, исключив их при этом из множества Y: Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»
  • 39. 39 X = {1, 5}; Y = {2, 3, 4, 6, 7} Теперь посмотрим, какую вершину можно было бы соеди- нить ребром с имеющейся сетью, затратив при этом минимум средств. Для этого рассмотрим все ребра с одной вершиной из множества X, а второй – из множества Y. Таких ребер у нас три: (1,2), (5, 4) и (5, 6). Из них выберем ребро наименьшего веса – это ребро (1,2). Добавляем это ребро к остову, а вершину 2 добавляем в множество X и исключаем из множества Y: X = {1, 2, 5}; Y = {3, 4, 6, 7} Снова ищем среди ребер, соединяющих вершины множества X с вершинами множества Y, то, которое имеет наименьший вес. Среди таких ребер ((2,3); (2,4); (5,4) и (5,6)) наименьший вес (9) имеет ребро (2,3), которое мы и добавляем к остову. Вершина 3 в свою очередь добавляется к X и исключается из Y: X = {1, 2, 3, 5}; Y = {4, 6, 7} Вершины множества X соединяют с вершинами множества Y следующие ребра: (2,4), (3,4), (3,6), (3,7), (5,4) и (5,6). Наимень- шим весом среди них (6) обладает ребро (3,7). Его включаем в Copyright ОАО «ЦКБ «БИБКОМ» & ООО «Aгентство Kнига-Cервис»