Задача о кратчайших путях между всеми парами узлов.
В предыдущих параграфах этой главы рассматривались задачи нахождения оптимальных в том или ином смысле путей от некоторого фиксированного узла до всех остальных узлов сети. Здесь мы рассмотрим задачу построения кратчайших путей между всеми парами узлов. Под длиной пути, также как и ранее в параграфах 1-3, понимаем сумму весов дуг, образующих этот путь. Ясно, что эту задачу можно решать, используя n раз (поочередно для каждого узла) один из описанных ранее алгоритмов нахождения расстояний от фиксированного узла. Таким образом, мы получаем алгоритмы сложности O(n4) (при использовании алгоритма Форда-Беллмана) и O(n3) для сетей с неотрицательными весами (алгоритм Дейкстры) или для бесконтурных сетей (алгоритм 6.6). Однако, для общего случая сетей с произвольными весами имеются более эффективные алгоритмы, чем метод, основанный на п-кратном применении алгоритма Форда-Беллмана. Один из таких алгоритмов, предложенный в 1962 году Флойдом, мы здесь и разберем.
Пусть сеть G=(V,E,c) задана матрицей весов А, где А| i,j | c(vi,vj), и A[i,j]=+∞, если дуги (vi,vj) в сети нет.
Обозначим через dk(i,j) длину кратчайшего пути из vi и vj, все промежуточные узлы которого содержатся в множестве {v1,...,vk}, то есть содержатся в первых к узлах. Будем считать, что d1(i,j)=A[i,j]. Пусть dk(i,j) вычислено для всех i,j=l,...,n, и некотором k≥1. Докажем равенство
dk+1(i,j) = min(dk(i,j), dk(i,k+l) + dk(k+l, j)). (6.5)
Действительно, рассмотрим кратчайший vi-vj-путь р с промежуточными узлами из множества {v1,…,vk,vk+1}. Возможны две ситуации: либо узел vk+1 входит в этот путь, либо нет.
Если узел vk+1 не входит в путь р, то, как легко видеть, справедливо равенство dk+1(i,j)= dk(i,j).
Если же узел vk+1 входит в путь р, то разбивая это путь на пути от v, до vk+1 и от vk+1 до vj, получаем два новых пути, все промежуточные узлы которых входят во множество {v1,...,vk}. Поскольку всякий подпуть кратчайшего пути сам является кратчайшим путем между соответствующими узлами, то справедливо равенство dk+1(i,j) = dk(i,k+l) + dk(k+l,j)), что завершает обоснование равенства (6.5).
Равенство (6.5) позволяет легко вычислять расстояния между всеми парами узлов, последовательно вычисляя для всех пар узлов значения d1(i,j). d2(i,j),..., dn(i,j), так как расстояние от v1 до vj равно dn(i,j).
Для нахождения самих кратчайших путей будем использовать аналог неоднократно применявшегося ранее массива ОТЕЦ, а именно, заведем матрицу ПРЕД размера n n, в которой ПРЕД[i,j] дает номер узла, являющегося предпоследним в кратчайшем vi-vj- пути (понятно, что последним узлом в таком пути является узел vj). Если k=ПРЕД[i,j], то, посмотрев значение ПРЕД[i,k], получим следующий узел в vi-vj-пути. Таким образом, двигаясь по элементам матрицы ПРЕД, легко построить путь для любой пары узлов.
Детали изложены в алгоритме 6.9, где предполагается, что A[i,i]=0, A[i,j]=+∞, если (vi,vj) Е. Еще раз повторим, что неотрицательность весов дуг не предполагается, но считается, что в сети нет контуров отрицательной длины.
АЛГОРИТМ 6.10 ФЛОЙД
(* Вычисление расстояний между всеми парами узлов *)
Данные: Сеть G=(V,E,c), заданная матрицей весов А[...n, 1...n].
Результаты: Расстояния D[i,j] для всех пар vi, vj V. матрица ПРЕД, в которой ПРЕД[v] равно номеру предпоследнего узла в кратчайшем vi-vj -пути.
Понятно, что сложность алгоритма 6.10 определяется сложностью цикла в строках 5-9, который состоит из трех вложенных циклов, выполняемых n раз каждый. Отсюда следует
Теорема 6.7. Алгоритм Флойда имеет сложность O(n3).
Здесь интересно отметить, что точно такую же сложность имеет алгоритм Форда-Беллмана вычисления расстояний от фиксированного узла до всех остальных узлов сети. В настоящее время не известен ни один алгоритм вычисления расстояния между фиксированной парой узлов, который был бы существенно эффективнее (то есть имел бы меньшую вычислительную сложность), чем алгоритм вычисления расстояний между всеми парами узлов. Впрочем, неизвестно также существует или нет такой алгоритм.
Формальное описание процедуры построения самих кратчайших путей, использующее в качестве исходных данных матрицу ПРЕД, не составляет никаких трудностей, и мы предоставляем его читателям в качестве несложного упражнения для самостоятельной работы.
Завершим главу рассмотрением примера, иллюстрирующего работу алгоритма Флойда.
Результаты работы цикла в строках 2-6:
D= ПЕРЕД=
Результаты работы цикла в строках 7-13 при k=1
D= ПЕРЕД=
Результаты работы цикла в строках 7-13 при k=2
D= ПЕРЕД=
Результаты работы цикла в строках 7-13 при k=3
D= ПЕРЕД=
Нетрудно проверить, что обе эти матрицы останутся неизменными в результате работы цикла 7-13 при k = 4. Вот кратчайшие пути для некоторых пар узлов: 2-4: 2-3-1-4; 1-3: 1-2-3; 3-2: 3-1-2.
Дата добавления: 2021-07-22; просмотров: 287;