- •Предназначено студентам очной формы обучения.
- •Введение
- •1. Оценки сложности алгоритмов
- •1.1. Определение понятия алгоритм
- •1.2. Оценка сложности алгоритмов
- •2. Линейные структуры данных
- •2.1. Методы организации и хранения линейных списков
- •2.2. Операции со списками при последовательном хранении
- •2.3. Операции со списками при связном хранении
- •2.4. Организация двусвязных списков
- •Задания для самоконтроля
- •2.5. Стеки и очереди
- •2.6. Сжатое и индексное хранение линейных списков
- •3. Сортировка и слияние
- •3.1. Пузырьковая сортировка
- •3.2. Сортировка вставкой
- •3.3. Сортировка посредством выбора
- •3.4. Сортировка квадратичной выборкой
- •3.5. Слияние списков
- •3.6. Сортировка списков путем слияния
- •3.7. Быстрая и распределяющая сортировки
- •4. Поиск
- •4.1. Последовательный поиск
- •4.2. Бинарный поиск
- •4.4. Методы вычисления адреса
- •4.5. Выбор в линейных списках
- •5. Рекурсия
- •6. Алгоритмы на графах и сетях
- •6.1. Исходные понятия
- •6.2. Матричные представления графов
- •6.3. Другие представления графов
- •6.4. Поиск в глубину как система исследования графа
- •6.5. Перебор цепей поиском в глубину
- •6.6. Взвешенные графы. Ориентированные графы
- •6.7. Нахождение фундаментального множества циклов
- •6.8. Выявление мостов и точек сочленений
- •6.9. Поиск в ширину как система исследования графа
- •6.10. Кратчайшие пути, ведущие от заданного узла X ко всем прочим
- •6.11. Алгоритм Дейкстры нахождения кратчайших путей во взвешенном графе
- •6.12. Улучшения алгоритма Дейкстры
- •6.13. Построение кратчайшего каркаса
- •6.14. Нахождение всевозможных кратчайших путей в графе
- •6.15. Потоковые задачи
- •6.16. Пример практической задачи на графах
- •7. Генераторы случайных и псевдослучайных последовательностей
- •7.1. Общая постановка задачи
- •7.3. Генератор случайных чисел, поставляемый с системой
- •7.4. Генератор с малым кодом
- •7.5. Генератор Парка-Миллера
- •7.6. Улучшенная версия генератора Парка-Миллера
- •7.7. Быстрый генератор для 32-битового представления целых и действительных чисел
- •7.8. Алгоритм л'Экюера, комбинирующий две последовательности
- •Оглавление
- •7. Генераторы случайных и псевдослучайных последовательностей 144
- •394026 Воронеж, Московский просп., 14
6.14. Нахождение всевозможных кратчайших путей в графе
При использовании и отрицательных весов ребер в графе могут быть циклы отрицательной длины. Такие циклы не допускаются описываемым ниже методом Флойда вычисления (за время О(n3)) расстояний между всеми парами узлов: применяют другие, не столь быстрые методы.
Ошибочно считают, что решение той же задачи алгоритмом Дейкстры имеет оценку О(n4) Мы убедимся в том, что модифицированный алгоритм, работающий по методу Деикстры, имеет оценку не хуже, чем у метода Флойда, а в разреженных графах - намного лучшую.
Метод Флойда непосредственно основывается на том факте, что в графе с положительными весами ребер или дуг всякий неэлементарный (содержащий более I ребра) кратчайший путь состоит из других кратчайших путей. В самом деле, если бы какая-либо составляющая не была кратчайшим путем, замена ее этим путем привела бы к уменьшению общей суммы длин, что противоречит исходной посылке.
Расстояние Dij между узлами i, j - элемент матрицы D, другая матрица R нужна для запоминания полученных кратчайших путей. Вначале Dij приравнивается весу ребра {i, j}, а если такого ребра нет 4 величиной заведомо большей, чем длина любого пути в графе (мы будем использовать значение Maxlnt). Затем узел m (m=l...n) проверяется как возможный промежуточный узел кратчайшего пути < i → j >: если сумма Dim + Dmj меньше Dij, Dij получает значений этой суммы и m запоминается как промежуточный узел. Если при другом значении m сумма будет еще меньше, запоминается эта сумма и это m, а старые - теряются. Узел m опробуется для всех пар (i, j). Обоснование метода приводится в [10], а очередность действий уточняет следующая весьма простая их запись:
For i:= 1 to n do {Матрица смежности А считается заданной}
Begin For j:= 1 to n do
Begin If A[i, j] = 0 {Нетребра (i, j)} Then D[i, j]:= Maxlnt ElseD[i, j]:= A[i,j]; R[i,j]:= 0;
End; D[i, i]:= 0
End (формирования исходных матриц D и R},
For m:= 1 to n do {3-кратный цикл нахождения кратчайших путей]
For i:= 1 to n do For j:= 1 to n do Begin g:= D[i,m] + D[m,j];
If D[i,j] > g Then Begin D[i,j]:= g; R[i,j]:= m End
End;
Сложностью формирования исходных матриц можно пренебречь, ибо очевидна большая сложность трехкратного цикла: О(n3).
Для предстоящего "честного соревнования" методов укажем на улучшение метода Флойда. В не-орграфах кратчайшие пути <i → j>, <j → i>, содержат одни и те же ребра и оценки их одинаковы, поэтому самый внутренний цикл трехкратного цикла записываем по-иному, почти, • вдвое сокращая время работы процессора типа Pentium:
For j:= i+1 to П do {ТОЛЬКОДЛЯ HE-ОРГРАФОВ!}
Begin g:= D[i,m] + D[m,j]; If D[ij] > g Then
Begin D[i,j]:= g; R[ij]:= m; D[j,i]:= g; R[j,i]:= m End
End;
Для вывода пути <i → j> применяем блок KPut с рекурсивной процедурой Put (блок ВЫПИСАТЬ ПУТЬ из [ 10) не рекомендуется): j
Procedure KPut(i,j:word);
Procedure Put(i,j:word); Begin If (R[i,j] = 0) And (i <> j) Then Write(' ', j)
Else Begin Put(i, R[i,j]); Put(R[i,j], j) End
End {рекурсивнойпроцедуры Put]
Begin Write(i); Put(i.j); Writeln
End;
Применяя n раз модифицированный метод Дейкстры для решения той же задачи, мы ожидаем, что сложность не будет хуже О(т • n • log n). Для полных (почти полных) графов улучшения не будет, но если, например, взять класс графов, в котором m линейно зависит от n, мы получим сложность О(n2 • log n). Упрощая, считаем рамками, в которых изменяется сложность, О(n2) и О(n3).
Заметим, что в i-ю строку матрицы D заносятся расстояния от i-гo узла до всех прочих и это происходит при i-м запуске алгоритма Дейкстры (D-поиске от i-гo узла). Заполняя строку, можно получить и некоторые элементы следующих строк. Если, например, кратчайший путь <5 → 8> получен как список узлов 5, 4, 6, 11, 8, то мы имеем и кратчайшие пути <6 → 8>, <11 → 8>. Кроме того, в не орграфе получаем кратчайшие пути <8 → 6>, <8 →11> и <8 → 5>. Пути <4 → 8> и <8 → 4> были получены раньше, при формировании 4-й строки матрицы D.
Итак, в момент i-гo запуска алгоритма уже имеется множество узлов с постоянными оценками, поэтому в программу добавлена часть, находящая непостоянные оценки всех смежных с ними узлов и формирующая сортдерево. В приложении 4 даны сравнительные характеристики рассмотренных методов для орграфов и не-орграфов, показывающие, что данный вариант метода Дейкстры в 1,5 раза быстрее метода Флойда в классе графов большой полноты и в несколько раз быстрее в классе графов малой полноты. При этом учтена модификация метода Флойда*. В этом же приложении даны соответствующие программы.
Заметим, что матрица R отлична от используемой в методе Флойда: i-я ее строка описывает D-каркас с корнем в i-м узле, используемый для вывода путей <i → любой узел > (см. блок KorPut в приложении 4).
Метод Флойда привлекает компактностью записи и применяется, например, при эпизодическом решении указанной задачи. Методы ее решения для общего случая и другие подходы см. в [10].
Задание 5.14.
Реализуйте метод Флойда в исходном и модифицированном варианте. Сравните производительность.