Алгоритм Флойда — Уоршелла

Автор работы: Пользователь скрыл имя, 21 Мая 2013 в 12:58, доклад

Описание работы

Если граф не содержит рёбер с отрицательным весом, то для решения этой проблемы можно использовать алгоритм Дейкстры для нахождения кратчайшего пути от одной вершины до всех остальных, запустив его на каждой вершине. Время работы такого алгоритма зависит от типа данных, который мы будем использовать для алгоритма Дейкстры, это может быть как простая очередь с приоритетом, так и бинарная или фибоначчиева Куча, соответственно время работы будет варьироваться от O(V3) до O(V*E*log(V)), где V количество вершин, а E — рёбер. («О»-большое).

Файлы: 1 файл

ТОИ.docx

— 208.25 Кб (Скачать файл)

МГПИ им. М.Е. Евсевьева

 

 

 

 

 

 

Доклад по ТОИ  на тему:

Алгоритм Флойда — Уоршелла.

 

 

 

 

Выполнил: студент группы МДИ-110 Рябов Евгений

Проверила: Пауткина Ольга Ивановна

 

 

 

 

 

Алгоритм Флойда — Уоршелла

Алгоритм Флойда — Уоршелла — алгоритм для нахождения кратчайших расстояний между всеми вершинами взвешенного графа без циклов с отрицательными весами с использованием метода динамического программирования. Это базовый алгоритм, так что тем кто его знает — можно дальше не читать. 
 
Этот алгоритм был одновременно опубликован в статьях Роберта Флойда (Robert Floyd) и Стивена Уоршелла (Stephen Warshall) в 1962 г., хотя в 1959 г. Бернард Рой (Bernard Roy) опубликовал практически такой же алгоритм, но это осталось незамеченным.

Ремарка

Если граф не содержит рёбер с  отрицательным весом, то для решения  этой проблемы можно использовать алгоритм Дейкстры для нахождения кратчайшего пути от одной вершины до всех остальных, запустив его на каждой вершине. Время работы такого алгоритма зависит от типа данных, который мы будем использовать для алгоритма Дейкстры, это может быть как простая очередь с приоритетом, так и бинарная или фибоначчиева Куча, соответственно время работы будет варьироваться от O(V3) до O(V*E*log(V)), где V количество вершин, а E — рёбер. («О»-большое). 
 
Если же есть рёбра с отрицательным весом, можно использовать алгоритм Беллмана — Форда. Но этот алгоритм, запущенный на всех вершинах графа, медленнее, время его работы O(V2*E), а в сильно «густых» графах аж O(V4).

Динамическое программирование

 
Что значит динамический алгоритм? Динамическое программирование — это альтернатива решению задач методом «в лоб», то есть brute forc'ом или жадными алгоритмами. Используется там, где оптимальное решение подзадачи меньшего размера может быть использовано для решения исходной задачи. В общем виде метод выглядит так: 
 
1. Разбиение задачи на подзадачи меньшего размера. 
2. Нахождение оптимального решения подзадач рекурсивно. 
3. Использование полученного решения подзадач для конструирования решения исходной задачи. 
 
Для нахождения кратчайших путей между всеми вершинами графа используется не перебор всех возможностей, что приведет к большому времени работы и потребует больше памяти, а восходящее динамическое программирование, то есть все подзадачи, которые впоследствии понадобятся для решения исходной задачи, просчитываются заранее и затем используются.

Структура кратчайшего пути

 
В основе алгоритма лежат два  свойства кратчайшего пути графа. Первое: 
 
Имеется кратчайший путь p1k=(v1,v2,… ,vk) от вершины v1 до вершины vk, а также его подпуть p'(vi,vi+1,… ,vj), при этом действует 1 <= i <= j <= k.

Если p — кратчайший путь от v1 до vk, то p' также является кратчайшим путем от вершины vi до vj

 
Это можно легко доказать, так  как стоимость пути p складывается из стоимости пути p' и стоимости  остальных его частей. Так вот  представив что есть более короткий путь p', мы уменьшим эту сумму, что приведет к противоречию с утверждением, что эта сумма и так уже была минимальной. 
 
Второе свойство является основой алгоритма. Мы рассматриваем граф G с пронумерованными от 1 до n вершинами {v1,v2,… ,vn} и путь pij от vi до vj, проходящий через определенное множество разрешенных вершин, ограниченное индексом k.  
 
То есть если k=0, то мы рассматриваем прямые соединения вершин друг с другом, так как множество разрешенных промежуточных вершин рано нулю. Если k=1 — мы рассматриваем пути, проходящие через вершину v1, при k=2 — через вершины {v1, v2}, при k=3 — {v1, v3, v3} и так далее.

Например у нас есть такой граф (слева) и k=1, то есть в качестве промужуточных узлов разрешен только узел «1». В этом графе при k=1 нет пути p43, но есть при k=2, тогда можно добраться из «4» в «3» через «2» или через «1» и «2». 
 
Рассмотрим кратчайший путь pij с разрешенными промужуточными вершинами {1..k-1} стоимостью dij. Теперь расширим множество на k- тый элемент, так что множество разрешенных вершин станет {1..k}. При таком расширении возможно 2 исхода: Случай 1. Элемент k не входит в кратчайший путь pij, то есть от добавления дополнительной вершины мы ничего не выиграли и ничего не изменили, а значит стоимость кратчайшего пути dkij не изменился, соответственно

dkij = dk-1ij — просто перенимаем значение до увеличения k.

 
Случай 2. Элемент k входит в кратчайший путь pij, то есть после добавления новой вершины в можество разрешенных, кратчайший путь изменился и проходит теперь через вершину vk. Какую стоимость получит новый путь? 
 
Новый кратчайший путь разбит вершиной vk на pik и pkj, используем первое свойство, согласно ему, pik и pkj также кратчайшие пути от vi до vk и от vk до vj соответственно. Значит 
 
dkij = dkik + dkkj 
 
А так как в этих путях k либо конечный, либо начальный узел, то он не входит в множество промежуточных, соответственно его из него можно удалить:

dkij = dk-1ik + dk-1kj

 

Алгоритм

 
Посмотрим на значение dkij в обоих случаях — верно! оно в обоих случаях складывается из значений d для k-1, а значит имея начальные (k=0) значения для d, мы сможем расчитать d для всех последующих значений k. А значения d для k=0 мы знаем, это вес/стоимость рёбер графа, то есть соединений без промужуточных узлов.  
 
При k=n (n — количество вершин) мы получим оптимальные значения d для всех пар вершин. 
 
При увеличении с k-1 до k, какое значение мы сохраним для dkik? Минимумом значений случая 1 и 2, то есть смотрим дешевле ли старый путь или путь с добавлением дополнительной вершины. 
 

Пример

 
 
 
Первый пересчет матрицы — изменяется одно значение, из-за расширения множества  разрешенных вершин на вершину «1»  мы смогли добраться от вершины «4»  до «2», используя более дешевый  путь. 
 
dkij = min( dk-1ij; dk-1ik + dk-1kj
 
d142 = min( d042, d041 + d012
 
d142 = min( 4, -1) 
 
Вторая итерация, улучшили значение для p43 
 
 
 
Результат 
 
Тут и там можно поиграть с аплетом и посмотреть как в живую работает алгоритм.

Анализ времени работы и использования памяти

 
Алгоритму требуется O(n3) памяти, для сохранения матриц. Однако количество матриц можно легко сократить до двух, каждый раз переписывая ненужную матрицу или вообще перейти к двухмерной матрице, убрав индекс k у dkij. Лучший вариант, который чаще всего используется — писать сразу в матрицу смежности, тогда нам совсем не нужна дополнительная память, правда если сразу переписывать изначальную матрицу, то нужно дополнительно показать корректность алгоритма, так как классическое академическоле доказательство верно только для случая, когда матрица предыдущей итерации не изменяется. 
 
Что касается времени работы — три вложенных цикла от 1 до n — Θ(n3).

Применение

 
Как и любой базовый алгоритм, алгоритм Флойда — Уоршелла используется очень широко и много где, начиная от поиска транзитивного замыкания графа, заканчивая генетикой и управлением проектами. Но первое что приходит в голову конечно же транспортные и всякие другие сети. 
 
Скажем если вы возьмете карту города — её транспортная система это граф, соответственно присвоив каждому ребру некую стоимость, расчитанную скажем из пропускной способности и других важный параметров — вы сможете подвести попутчика по самому короткому/быстрому/дешевому пути.

Саранск 2013

 


Информация о работе Алгоритм Флойда — Уоршелла