Первоначально опубликовано на Seedbx.com 2 декабря 2020 г.
Поиск кратчайшего пути во взвешенном графе — сложная задача, но поиск кратчайшего пути из каждой вершины в любую другую вершину — непростая задача.
В этом посте мы обсудим алгоритм Флойда-Уоршалла, который идеально подходит для этой работы.
Примечание. Во всех псевдокодах используется индексация на основе 0, а отступы используются для различения блоков кодов.
Постановка задачи
Пусть G — взвешенный ориентированный граф с положительным и отрицательным весом (но без отрицательных циклов), а V — множество всех вершин. Найдите длину кратчайшего взвешенного пути в G между каждой парой вершин в V.
Наивный подход
Самый простой способ найти длину кратчайшего пути между каждой парой вершин в графе — пройти все возможные пути между каждой парой вершин. В этом подходе мы собираемся использовать то свойство, что каждая часть оптимального пути сама по себе оптимальна.
Псевдокод:
minDistance[|V|][|V|]={inf}
findShortestPath(curr, dest)
if curr==dest return minDistance[curr][curr]=0 if visited[curr]==true return minDistance[curr][dest] visited[curr]=true sumOfWeights=minDistance[curr][dest]
for vertex in graph[curr] ctr=graph[curr][vertex]+findShortestPath(vertex, dest) if ctr<sumOfWeights sumOfWeights=ctr
return minDistance[curr][dest]=sumOfWeights
naive_approach() for start=0 upto |V| for dest=0 upto |V| visited[|V|]={false} foo=findShortestPath(start, dest)
Временная сложность: O(|V|2*( |V|+|E| ))
Пространственная сложность: O(|V|2)
Алгоритм Флойда-Уоршалла
Алгоритм Флойда-Уоршалла — это пример динамического программирования, опубликованный независимо друг от друга в 1962 году.
Подобно алгоритму Беллмана-Форда и алгоритму Дейкстры, он вычисляет кратчайший взвешенный путь в графе. Однако в отличие от алгоритма Беллмана-Форда и алгоритма Дейкстры, которые находят кратчайший путь из одного источника, алгоритм Флойда-Уоршалла находит кратчайший путь из каждой вершины графа.
Алгоритм сравнивает все возможные пути между каждой парой вершин в графе. Это достигается за счет улучшения оценки кратчайшего пути до тех пор, пока оценка не станет оптимальной. Алгоритм в основном проверяет, находится ли вершина k на кратчайшем пути между вершинами i и j.
Рекурсия
Определим shortestPath(i,j,k) как длину кратчайшего пути между вершиной i и вершиной j, используя только вершины из множества {1,2,3,…,k-1,k} в качестве промежуточных точек. . Наша цель — найти длину кратчайшего пути между всеми вершинами i и j в V, используя вершины из V в качестве промежуточных точек.
Для каждой пары вершин i и j:
- Кратчайший путь проходит через k, т. е. путь идет от i до k, а затем от k до j.
- Кратчайший путь не проходит через k.
Следовательно, рекурсивная формула выглядит следующим образом:
Базовый вариант:
shortestPath(i,j,0)=graph(i,j)
Рекурсивный вариант:
shortestPath(i ,j,k)=min(кратчайшийПуть(i,j,k-1), кратчайшийПуть(i,k,k-1)+кратчайшийПуть(k,j,k-1))
Алгоритм использует природу динамического программирования для эффективного выполнения этой рекурсии.
Псевдокод:
floydWarshall(graph, V, E)
minDistance[|V|][|V|]={inf}
// Initialising minDistance as the graph for edge=0 upto |E| u=edge.first v=edge.second minDistance[u][v]=graph[u][v] // Initialising minDistance for each vertex for vertex=0 upto |V| minDistance[vertex][vertex]=0
for mid=0 upto |V| for start=0 upto |V| for dest=0 upto |V| if minDistance[start][dest]>minDistance[start][mid]+minDistance[mid][dest] minDistance[start][dest]=minDistance[start][mid]+minDistance[mid][dest]
return minDistance
Временная сложность: O(|V|3)
Проблема с отрицательным циклом
Отрицательный цикл — это цикл, у которого сумма ребер в цикле отрицательна. Вершины в отрицательном цикле никогда не могут иметь кратчайшего пути, потому что мы всегда можем вернуться к отрицательному циклу, что уменьшит сумму весов и, следовательно, даст нам бесконечный цикл.
Однако для обнаружения отрицательных циклов можно использовать алгоритм Флойда-Уоршалла. Интуиция, стоящая за этим, заключается в том, что minDistance[v][v]=0 для любой вершины v, но если существует отрицательный цикл, выбор пути [v,….,C,….,v] уменьшит только кратчайший путь (где C — отрицательный цикл). Следовательно, если в графе существует отрицательный цикл, то в minDistance будет по крайней мере один отрицательный диагональный элемент.
Приложения
- Вычисление сходства между графами.
- Нахождение транзитивного замыкания взвешенного графа.
- Проверка того, является ли неориентированный граф двудольным.
- Определение того, содержит ли граф отрицательный цикл.
- Для поиска Оптимальной маршрутизации между вершинами.
На сегодняшний день алгоритм Флойда-Уоршалла является наиболее эффективным алгоритмом, подходящим для этой работы. Однако вы никогда не узнаете, что ждет нас в будущем.
Спасибо, что прочитали статью!
Если у вас есть вопросы, оставьте комментарий ниже. Не забудьте поставить аплодисменты, если вам понравилась статья.
Первоначально опубликовано на Seedbx.com 2 декабря 2020 г.