Изменения

Перейти к: навигация, поиск

Алгоритм Дейкстры

3112 байт добавлено, 19:30, 4 сентября 2022
м
rollbackEdits.php mass rollback
В ориентированном взвешанном графе {{Задача|definition=Для заданного взвешенного графа <tex>G = (V, E)</tex>, вес рёбер которого неотрицателен и определяется весовой функцией <tex>w(uv) \geqslant 0</tex>, Алгоритм Дейкстры находит длину кратчайшего найти кратчайшие пути из одной заданной вершины <tex>s</tex> до всех остальныхвершин. Веса всех рёбер неотрицательны.}}
== Алгоритм ==
Алгори́тм Де́йкстры В [[Ориентированный граф|ориентированном]] взвешенном [[Основные определения: граф, ребро, вершина, степень, петля, путь, цикл|графе]] <tex>G = (Dijkstra’s algorithmV, E) </tex>, вес [[Основные определения: граф, ребро, вершина, степень, петля, путь, цикл|рёбер]] которого неотрицателен и определяется весовой функцией <tex>w : E \to \mathbb{R}</tex>, алгоритм на графахДейкстры находит длины кратчайших [[Основные определения: граф, ребро, вершина, степень, петля, путь, изобретённый нидерландским ученым Э. Дейкстрой в 1959 году. Находит кратчайшее расстояние от одной цикл|путей]] из вершин графа заданной [[Основные определения: граф, ребро, вершина, степень, петля, путь, цикл|вершины]] <tex>s</tex> до всех остальных. Алгоритм работает только <br>В алгоритме поддерживается множество вершин <tex>U</tex>, для графов без которых уже вычислены длины кратчайших путей до них из <tex>s</tex>. На каждой итерации основного цикла выбирается вершина <tex> u \notin U</tex>, которой на текущий момент соответствует минимальная оценка кратчайшего пути. Вершина <tex>u</tex> добавляется в множество <tex>U</tex> и производится релаксация всех исходящих из неё рёбер отрицательного веса.
== Псевдокод ==
'''Dijkstrafunc'''dijkstra(s)''':''' '''for''' <tex>G</tex>, <tex>w</tex>, <tex>sv \in V</tex>) d[v] = <tex>d \gets \infty</tex> <tex> used[v] = ''false'' d[s] \gets = 0</tex> '''for''' <tex>S i \gets \varnothingin V</tex> v = ''null'while' '''for''' <tex>j \in V \setminus S \neq \varnothing</tex> <font color="green">// найдём вершину с минимальным расстоянием</font> '''if''do'!used[j] '' <tex>u \gets </tex> 'and'argmin''(v == ''null'' '''or''' d[j] <tex>d[v : ]) v \in V \setminus S, = j '''if''' d[v]== </tex>) <tex>S \gets S \cup \{u\}infty</tex> '''break'''for used[v] = ''true'' <tex>(uv) \in E</tex> '''dofor''' e : исходящие из ''relaxv''(рёбра <texfont color="green">u</tex>/ произведём релаксацию по всем рёбрам, <tex>исходящим из ''v''</texfont>, '''if''' d[v] + e.len <tex>w</tex>)d[e.to] d[e.to] = d[v] + e.len
== Обоснование корректности работы ==
{{Теорема
|statement=После окончания работы Пусть <tex>G = (V, E)</tex> {{---}} ориентированный взвешенный граф, вес рёбер которого неотрицателен, <tex>s</tex> {{---}} стартовая вершина.Тогда после выполнения алгоритма Дейкстры <tex>d(u) = \rho(s, u)</tex> для всех вершин <tex>u \in V</tex> будет выполняться равенство , где <tex>d[u] = \deltarho(s, u)</tex> {{---}} длина кратчайшего пути из вершины <tex>s</tex> в вершину <tex>u</tex>
|proof=
Рассмотрим инвариант основного цикла: в начале каждой итерации для всех вершин <tex>v \in S</tex> выполняется <tex>d[v] = \delta(s, v)</tex> '''Инициализация'''. Изначально множество <tex>S</tex> пусто, инвариант выполняется. [[Файл:DijkstraProove.png|thumb|right|Рис. 1]]'''Сохранение'''. ПокажемДокажем по индукции, что при каждой итерации инвариант сохраняется для каждой в момент посещения любой вершины, добавленной в <tex>S</tex>, для этого воспользуемся методом «от противного». Предположим, что <tex>u</tex> первая добавленная в <tex>S</tex> вершина, для которой равенство <tex>d[(u] ) = \deltarho(s, u)</tex> не выполняется. Рассмотрим ситуацию, сложившуюся в начале итерации, в которой <tex>u</tex> будет добавлена в <tex>S</tex>. Рассмотрев кратчайший путь из * На первом шаге выбирается <tex>s</tex> в <tex>u</tex>, можно получить противоречие, заключающееся в том, что на рассматриваемый момент справедливо равенство для неё выполнено: <tex>d[u] (s) = \deltarho(s, us)= 0</tex>. Должно выполняться условие * Пусть для <tex>u \neq sn</tex>, так как первых шагов алгоритм сработал верно и на <tex>sn + 1</tex> является первой вершиной, добавленной в шагу выбрана вершина <tex>Su</tex> и . Докажем, что в этот момент её добавления равенство <tex>d[(u] ) = \deltarho(s, u)</tex> выполняется. Из условия <tex>u \neq s</tex> следует, в частностиДля начала отметим, что <tex>S</tex> не пусто. Из для любой вершины <tex>sv</tex> в вершину <tex>u</tex> должен существовать какой-нибудь путь, так как иначе всегда выполняется соотношение <tex>d[u] = \delta(s, uv) = \infty</tex>, нарушающее предположение о том, что равенство <tex>d[u] = geqslant \deltarho(s, uv)</tex> (алгоритм не выполняется. Из существования пути следуетможет найти путь короче, что существует и чем кратчайший путь из всех существующих). Пусть <tex>pP</tex> — кратчайший путь из <tex>s</tex> в <tex>u</tex>. Перед добавлением , <tex>uv</tex> в {{---}} первая непосещённая вершина на <tex>SP</tex> путь , <tex>pz</tex> соединяет вершину из множества {{---}} предшествующая ей (следовательно, посещённая). Поскольку путь <tex>SP</tex> с вершиной принадлежащей множеству кратчайший, его часть, ведущая из <tex>V \setminus Ss</tex>. Рассмотрим первую вершину через <tex>yz</tex> на пути в <tex>p</tex> принадлежащую <tex>V \setminus Sv</tex>, и положимтоже кратчайшая, что её предшествует вершина следовательно <tex>x \in S</tex>. Тогдаrho(s, как видно из рис.1v) = \rho(s, путь <tex>p</tex> можно разложить на составляющие <tex>s \overset{p_1}{\leadsto} x \to y \overset{p_2}{\leadsto} uz) + w(zv)</tex>. УтверждаетсяПо предположению индукции, что в момент добавления посещения вершины <tex>uz</tex> в множество <tex>S</tex>, выполняется равенство выполнялось <tex>d[y] (z) = \deltarho(s, yz)</tex>. Так как , следовательно, вершина <tex>u</tex> выбрана как первая вершина, после добавления которой в множество <tex>Sv</tex> тогда получила метку не выполянется соотношение больше чем <tex>d[u] (z) + w(zv) = \rho(s, z) + w(zv) = \deltarho(s, uv)</tex>, то после добавления вершины <tex>x</tex> в <tex>S</tex> справедливо равенство следовательно, <tex>d[x] (v) = \deltarho(s, xv)</tex>. В это время происходит релаксация ребра <tex>xy</tex>С другой стороны, поэтому вышеописанное утверждение выполняется.  Поскольку на кратчайшем пути из <tex>s</tex> в поскольку сейчас мы выбрали вершину <tex>u</tex> вершина <tex>y</tex> находиться перед <tex>u</tex> и вес каждого из ребер выражается неотрицательным значением, выполняется неравенство её метка минимальна среди непосещённых, то есть <tex>\deltad(s, yu) \leqslant \deltad(s, uv)</tex>, поэтому <tex>d[y] = \deltarho(s, yv) \leqslant \deltarho(s, u) \leqslant d[u]</tex>. Но так как и вершина <tex>u</tex>, и вершина <tex>y</tex> во время выбора где второе неравенсто верно из-за ранее упомянутого определения вершины <tex>uv</tex> находились в множестве качестве первой непосещённой вершины на <tex>V \setminus SP</tex>, выполняется неравенство <tex>d[u] \leqslant d[y]</tex>то есть вес пути до промежуточной вершины не превосходит веса пути до конечной вершины вследствие неотрицательности весовой функции. Таким образом, оба Комбинируя это с <tex>d[y] = \delta(s, yu) = \deltageqslant \rho(s, u) = d[u]</tex>. Значит, имеем <tex>d[u] = \delta(s, u)</tex>, что противоречит нашему выбору вершины <tex>u</tex>. Следовательно, во время добавления вершины <tex>u</tex> в множество <tex>S</tex> выполняется равенство<tex>d[u] = \deltarho(s, u)</tex>, а следовательно, оно выполняется что и в дальнейшемтребовалось доказать.
'''Завершение'''. По завершении работы алгоритма множество *Поскольку алгоритм заканчивает работу, когда все вершины посещены, в этот момент <tex>V d(u) = \setminus S</tex> пусто. Из этого равенства следуетrho(s, что <tex>S = Vu)</tex>. Таким образом, для всех вершин <tex>u \in V</tex> выполняется равенство <tex>d[u] = \delta(s, u)</tex>.
}}
== Оценка сложности ==
Основной цикл выполняется <tex>V</tex> раз. Релаксация выполниться всего В реализации алгоритма присутствует функция выбора вершины с минимальным значением <tex>Ed</tex> рази релаксация по всем рёбрам для данной вершины. В реализации алгоритма присутствует функция ''argmin'', асимптотика её Асимптотика работы зависит от реализации.
Таким образом:Пусть <tex>n</tex> {{| border="1" cellpadding="5" cellspacing="0" style="text-align:center" width=30%!style="background:#f2f2f2"|Структура данных для хранения множества --}} количество вершин в графе, <tex>V \setminus Sm</tex>{{---}} количество рёбер в графе.!style{| class="background:#f2f2f2wikitable"|Асимптотика времени работы
|-
! rowspan="2" |style! colspan="background:#f9f9f93"|Наивная реализацияВремя работы|style! rowspan="background:#f9f9f92"|<tex>O(V^2+E)</tex>Описание
|-
|style="background:#f9f9f9"|Куча! Поиск минимума|style="background:#f9f9f9"|<tex>O(E\log{V})</tex>! Релаксация! Общее
|-
|stylealign="background:#f9f9f9center"|Куча ФибоначчиНаивная реализация|stylealign="background:#f9f9f9center"|<tex>O(Vn)</tex>| align="center" | <tex>O(1)</tex>| align="center" | <tex>O(n^2 + m)</tex>| align="center" | <tex>n</tex> раз осуществляем поиск вершины с минимальной величиной <tex>d</tex> среди <tex>O(n)</tex> непомеченных вершин и <tex>m</tex> раз проводим релаксацию за <tex>O(1)</tex>. Для плотных графов (<tex>m \approx n^2</tex>) данная асимптотика является оптимальной.|-| align="center" | [[Двоичная куча]]| align="center" | <tex>O(\log{n})</tex>| align="center" | <tex>O(\log{n})</tex>| align="center" | <tex>O(m\log{n})</tex>| align="center" | Используя двоичную кучу можно выполнять операции извлечения минимума и обновления элемента за <tex>O(\log{n})</tex>. Тогда время работы алгоритма Дейкстры составит <tex>O(n\log{n} + m\log{n}) = O(m\log{n})</tex>. |-| align="center" | [[Фибоначчиевы кучи|Фибоначчиева куча]]| align="center" | <tex>O(\log{n})</tex>| align="center" | <tex>O(1)</tex>| align="center" | <tex>O(n\log{n} + m)</tex>| align="center" | Используя Фибоначчиевы кучи можно выполнять операции извлечения минимума за <tex>O(\log{n})</tex> и обновления элемента за <tex>O(1)</tex>. Таким образом, время работы алгоритма составит <tex>O(n\log{Vn}+Em)</tex>.
|}
На практике удобно использовать стандартные контейнеры (например, '''std::set''' или '''std::priority_queue''' в C++). <br>При реализации необходимо хранить вершины, которые упорядочены по величине <tex>d</tex>, для этого в контейнер можно помещать пару {{---}} расстояние-вершина. В результате будут храниться пары, упорядоченные по расстоянию.
 
Изначально поместим в контейнер стартовую вершину <tex>s</tex>. Основной цикл будет выполняться, пока в контейнере есть хотя бы одна вершина. На каждой итерации извлекается вершина с наименьшим расстоянием <tex>d</tex> и выполняются релаксации по рёбрам из неё. При выполнении успешной релаксации нужно удалить из контейнера вершину, до которой обновляем расстояние, а затем добавить её же, но с новым расстоянием.
<br>В обычных кучах нет операции удаления произвольного элемента. При релаксации можно не удалять старые пары, в результате чего в куче может находиться одновременно несколько пар расстояние-вершина для одной вершины (с разными расстояниями). Для корректной работы при извлечении из кучи будем проверять расстояние: пары, в которых расстояние отлично от <tex>d[v]</tex> будем игнорировать. При этом асимптотика будет <tex>O(m\log{m})</tex> вместо <tex>O(m\log{n})</tex>.
== Литература Источники информации ==* ''Кормен, Томас Х., ЛейзерсонКормен, Чарльз И., РивестЛейзерсон, Рональд Л.Ривест, Клиффорд Штайн Клиффорд'' '''Алгоритмы: построение и анализ''', 2-е издание. Пер. с англизд. — М.:Издательский дом "Вильямс"«Вильямс», 20102007. — 1296 с.: ил. — Парал. тит. англ459. — ISBN 978-5-84598489-0857-5 (рус4* [http://e-maxx.ru/algo/dijkstra MAXimal :: algo :: Нахождение кратчайших путей от заданной вершины до всех остальных вершин алгоритмом Дейкстры]* [https://ru.wikipedia.org/wiki/Алгоритм_Дейкстры Википедия — Алгоритм Дейкстры]* [https://en.wikipedia.)org/wiki/Dijkstra%27s_algorithm Wikipedia — Dijkstra's algorithm]
[[Категория: Алгоритмы и структуры данных]]
[[Категория: Кратчайшие пути в графах ]]
1632
правки

Навигация