
- •Иркутский государственный технический университет
- •1. Определения графов
- •7.4.5. Массив дуг
- •8.4.2. Трансверсаль
- •8.5.4. Алгоритм нахождения максимального потока
- •8.6.3. Выделение компонент сильной связности
- •8.7.1. Длина дуг
- •8.7.2. Алгоритм Флойда
- •8.7.3. Алгоритм Дейкстры
- •Глава 9 Деревья
- •9.1. Свободные деревья
- •9.1.1. Определения
- •9.1 .2. Основные свойства деревьев
- •9.2. Ориентированные, упорядоченные и бинарные деревья
- •9.2.1. Ориентированные деревья
- •9.2.2. Эквивалентное определение ордерева
- •9.2.3. Упорядоченные деревья
- •9.2.4. Бинарные деревья
- •9.3. Представление деревьев в эвм
- •9.3.1. Представление свободных, ориентированных и упорядоченных деревьев
- •9.3.2. Представление бинарных деревьев
- •9.3.3. Обходы бинарных деревьев
- •9.3.4. Алгоритм симметричного обхода бинарного дерева
- •9.4. Деревья сортировки
- •9.4.1. Ассоциативная память
- •9.4.2. Способы реализации ассоциативной памяти
- •9.4.3. Алгоритм бинарного (двоичного) поиска
- •9.4.4. Алгоритм поиска в дереве сортировки
- •9.4.5. Алгоритм вставки в дерево сортировки
- •9.4.6. Алгоритм удаления из дерева сортировки
- •9.4.7. Вспомогательные алгоритмы для дерева сортировки
- •9.4.8. Сравнение представлений ассоциативной памяти
- •9.4.9. Выровненные деревья
- •9.4.10. Сбалансированные деревья
- •9.5. Кратчайший остов
- •9.5.1. Определения
- •9.5.2. Схема алгоритма построения кратчайшего остова
- •9.5.3. Алгоритм Краскала
- •Глава 10 Циклы
- •10.1. Фундаментальные циклы и разрезы
- •10.1.1. Циклы и коциклы
- •10.1.2. Независимые множества циклов и коциклов
- •10.1.3. Циклический и коциклический ранг
- •10.2. Эйлеровы циклы
- •10.2.1. Эйлеровы графы
- •10.2.2. Алгоритм построения эйлерова цикла в эйлеровом графе
- •10.2.3. Оценка числа эйлеровых графов
- •10.3. Гамильтоновы циклы
- •10.3.1. Гамильтоновы графы
- •10.3.2. Задача коммивояжера
- •Глава 11 Независимость и покрытия
- •11.1. Независимые и покрывающие множества
- •11.1.1. Покрывающие множества вершин и ребер
- •11.1.2. Независимые множества вершин и ребер
- •11.1.3. Связь чисел независимости и покрытий
- •11.2. Построение независимых множеств вершин
- •11.2.1. Постановка задачи отыскания наибольшего независимого множества вершин
- •11.2.2. Поиск с возвратами
- •11.2.3. Улучшенный перебор
- •11.2.4. Алгоритм построения максимальных независимых множеств вершин
- •11.3. Доминирующие множества
- •11.3.1. Определения
- •11.3.2. Доминирование и независимость
- •11.3.3. Задача о наименьшем покрытии
- •11.3.4. Эквивалентные формулировки знп
- •11.3.5. Связь знп с другими задачами
- •Глава 12 Раскраска графов
- •12.1. Хроматическое число
- •Ух, . . . ,Vn одноцветные классы,доказательство
- •12.2. Планарность
- •12.2.2. Эйлерова характеристика
- •12.2.3. Теорема о пяти красках
- •12.3. Алгоритмы раскрашивания
- •12.3.1. Точный алгоритм раскрашивания
- •12.3.2. Приближенный алгоритм последовательного раскрашивания
- •12.3.3. Улучшенный алгоритм последовательного раскрашивания
8.6.3. Выделение компонент сильной связности
Следующий алгоритм, основанный на методе поиска в глубину, находит все компоненты сильной связности орграфа.
Алгоритм 8.2. Выделение компонент сильной связности Вход: орграф G(V, Е), заданный списками смежности Г(г;).
Выход: список С компонент сильной связности, каждый элемент которого есть список вершин, входящих в компоненту сильной связности. С: = 0 for v e V do
M[v]: ={v} { M[v] список вершин, входящих в ту же КСС, что и v }
e[v]: = 0 { все вершины не рассмотрены } end for while V ф 0 do
select v g V { взять v из V }
Т <— v { положить v в стек }
е[г>]: = 1 { отметить v }
КСС { вызов процедуры КСС } end while
Основная работа выполняется рекурсивной процедурой без параметров КСС, которая использует стек Т для хранения просматриваемых вершин. Процедура КСС выделяет все КСС, достижимые из вершины, выбранной в основном алгоритме.
if Т = 0 then
return{ негде выделять }
end if
v <— Т; v —» Т { стоим в вершине г>} if T[v] П V = 0 then
C: = C\JM[v] {этоКСС } V : = V \ {v} { удалить вершину } v «— Т { снять г) со стека } КСС { возврат из тупика } else
for и 6 Г[г>] do if e[u] = 0 then u —> Г { положить и в стек } е[и]: = 1 { отметить и } else repeat
w <— Т { ш — склеиваемая вершина } \/ : = V \ {w} { удалить ее } Г [и]: = Г [и] U Г [ад] { запомнить смежность } М[и] : = М[и} U М[го]{ склеивание вершин } until и = w
w —>• Т{ чтобы не убрать ту вершину, } V : = V U {w}{ к которой слили } end if
КСС { поиск в глубину }
end for
end if
Кратчайшие пути
Задача нахождения кратчайшего пути в графе имеет столько практических применений и интерпретаций, что читатель, без сомнения, может сам легко привести множество примеров. Здесь рассматриваются два классических алгоритма, которые обязан знать каждый программист.
8.7.1. Длина дуг
Алгоритм Уоршалла позволяет ответить на вопрос, существует ли цепь (и, и). Часто нужно не только определить, существует ли цепь, но и найти эту цепь. Если задан орграф G(V, E), в котором дуги помечены числами (эти числа обычно называют весами, или длинами, дуг), то этот орграф можно представить в виде матрицы весов (длин) С:{ О, для г = j Cij, конечная величина, если есть дуга из г в j, оо, если нет дуги из г в j.
Длиной пути называется сумма длин дуг, входящих в этот путь. Наиболее часто на практике встречается задача отыскания кратчайшего пути.
8.7.2. Алгоритм Флойда
Алгоритм Флойда находит кратчайшие пути между всеми парами вершин в (ор)графе. В этом алгоритме для хранения информации о путях используется матрица Н[1..р, 1..р], где
., _ J k, если k— первая вершина, достигаемая на кратчайшем пути из г в j; (О, если из i в j нет пути.
ОТСТУПЛЕНИЕ
Матрица Н размера О(р2) хранит информацию обо всех (кратчайших) путях в графе. Заметим, что всего в графе О(р2) путей, состоящих из О(р) вершин. Таким образом, непосредственное представление всех путей потребовало бы памяти объема О(р3). Экономия памяти достигается за счет интерпретации представления, то есть динамического вычисления некоторой части информации вместо ее хранения в памяти. В данном случае любой конкретный путь (и, v) легко извлекается из матрицы с помощью следующего алгоритма.
w: =u; yield w{ первая вершина }
while w ^ v do
w : = H[w, v}; yield w{ следующая вершина }
end while
Алгоритм 8.З. алгоритм Флойда Вход: матрица С[1..р, 1..р] длин дуг.
Выход: матрица Т[1..р,1..р] длин путей и матрица Н[1..р,1..р] самих путей. for г from I to p do for j from 1 to p do T[i,j] : = C[i,j] { инициализация } if C[iJ] = 00 then
H[i,j\: = 0 { нет дуги из г в j } else
H[i,j] -=j{ есть дуга из г в j } end if end for end for
for г from 1 to p do for j from 1 to p do for fc from 1 to p do
if г + jkT{j,i] / <х>&г ф k&T{i,k] / oo&(T[j,fc] = ooVT[j,k] > T\ then
H[j, k]: = H[j, i] { запомнить новый путь } T[j, k]: = T[j, i] + T[i, k} { и его длину } end if end for end for
for j from 1 to p do if T,j <0then
stop { нет решения: вершина j входит в цикл отрицательной длины } end if end for end for
ЗАМЕЧАНИЕ -
Если в G есть цикл с отрицательным весом, то решения поставленной задачи не существует, так как можно «накручивать» на этом цикле сколь угодно короткий путь.
обоснование
Алгоритм Флойда имеет много общего с алгоритмом Уоршалла (алгоритм 1.8). Покажем по индукции, что после выполнения г-го шага основного цикла по г элементы матриц T\j,k\ и H[j,k] содержат, соответственно, длину кратчайшего пути и первую вершину на кратчайшем пути из вершины j в вершину k, проходящем через промежуточные вершины из диапазона 1..г. База: г = 0, то есть до начала цикла элементы матриц Т и Н содержат информацию о кратчайших путях (если таковые есть), не проходящих ни через какие промежуточные вершины. Пусть теперь перед началом выполнения тела цикла на г-м шаге T[j, k] содержит длину кратчайшего пути от j к k , a H[j,k] содержит первую вершину на кратчайшем пути из вершины j в вершину k (если таковой есть). В таком случае, если в результате добавления вершины г к диапазону промежуточных вершин находится более короткий путь (в частности, если это вообще первый найденный путь), то он записывается. Таким образом, после окончания цикла, когда г = р, матрицы содержат кратчайшие пути, проходящие через промежуточные вершины 1..р, то есть искомые кратчайшие пути. Алгоритм не всегда выдает решение, поскольку оно не всегда существует. Дополнительный цикл по j служит для прекращения работы в случае обнаружения в графе цикла с отрицательным весом.