Алгоритм Дейкстры — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 15: Строка 15:
 
     '''for''' <tex>i \in V</tex>
 
     '''for''' <tex>i \in V</tex>
 
         v = ''null''
 
         v = ''null''
         '''for''' <tex>j \in V</tex>                 <font color="green">// найдем вершину с минимальным расстоянием</font>
+
         '''for''' <tex>j \in V</tex>                       <font color="green">// найдем вершину с минимальным расстоянием</font>
 
             '''if''' !used[j] '''and''' (v == ''null'' '''or''' d[j] < d[v])
 
             '''if''' !used[j] '''and''' (v == ''null'' '''or''' d[j] < d[v])
 
                 v = j
 
                 v = j
Строка 39: Строка 39:
  
 
== Оценка сложности ==
 
== Оценка сложности ==
Основной цикл выполняется <tex>V</tex> раз. Релаксация выполнится всего <tex>E</tex> раз. В реализации алгоритма присутствует функция выбора вершины с минимальным значением <tex>d</tex>, асимптотика её работы зависит от реализации.
+
В реализации алгоритма присутствует функция выбора вершины с минимальным значением <tex>d</tex> и релаксация по всем рёбрам для данной вершины. Асимптотика работы зависит от реализации.
  
Таким образом:
+
Пусть <tex>n</tex> - количество вершин в графе, <tex>m</tex> - количество рёбер в графе.
  
{| border="1" cellpadding="5" cellspacing="0" style="text-align:center"
+
{| class="wikitable"
! Структура данных
 
! Время работы
 
 
|-
 
|-
|Наивная реализация
+
! rowspan="2" |
|<tex>O(V^2+E)</tex>
+
! colspan="3" | Время работы
 +
! rowspan="2" | Описание
 
|-
 
|-
|[[Двоичная куча]]
+
! Поиск минимума
|<tex>O(E\log{V})</tex>
+
! Релаксация
 +
! Общее
 
|-
 
|-
|[[Фибоначчиевы кучи|Фибоначчиева куча]]
+
| align="center" | Наивная реализация
|<tex>O(V\log{V}+E)</tex>
+
| align="center" | <tex>O(n)</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{n} + m)</tex>.
 
|}
 
|}
  

Версия 19:21, 27 декабря 2015

Задача:
Для заданного взвешенного графа [math]G = (V, E)[/math] найти кратчайшие пути из заданной вершины [math] s [/math] до всех остальных вершин. Веса всех рёбер неотрицательны.


Алгоритм

В ориентированном взвешенном графе [math]G = (V, E)[/math], вес рёбер которого неотрицателен и определяется весовой функцией [math]w : E \to \mathbb{R}[/math], алгоритм Дейкстры находит длины кратчайших путей из заданной вершины [math]s[/math] до всех остальных.
В алгоритме поддерживается множество вершин [math]U[/math], для которых уже вычислены длины кратчайших путей до них из [math]s[/math]. На каждой итерации основного цикла выбирается вершина [math] u \notin U[/math], которой на текущий момент соответствует минимальная оценка кратчайшего пути. Вершина [math]u[/math] добавляется в множество [math]U[/math] и производится релаксация всех исходящих из неё рёбер.

Псевдокод

func dijkstra(s):
    for [math]v \in V[/math]                    
        d[v] = [math]\infty[/math]
        used[v] = false
    d[s] = 0
    for [math]i \in V[/math]
        v = null
        for [math]j \in V[/math]                        // найдем вершину с минимальным расстоянием
            if !used[j] and (v == null or d[j] < d[v])
                v = j
        if d[v] == [math]\infty[/math]
            break
        used[v] = true
        for e : исходящие из v рёбра     // произведём релаксацию по всем рёбрам, исходящим из v
            if d[v] + e.len < d[e.to]
                d[e.to] = d[v] + e.len

Обоснование корректности

Теорема:
Пусть [math]G = (V, E)[/math] — ориентированный взвешенный граф, вес рёбер которого неотрицателен, [math]s[/math] — стартовая вершина. Тогда после выполнения алгоритма Дейкстры [math]d(u) = \rho(s, u)[/math] для всех [math]u[/math], где [math]\rho(s, u)[/math] — длина кратчайшего пути из вершины [math]s[/math] в вершину [math]u[/math]
Доказательство:
[math]\triangleright[/math]

Докажем по индукции, что в момент посещения любой вершины [math]u[/math], [math]d(u) = \rho(s, u)[/math].

  • На первом шаге выбирается [math]s[/math], для нее выполнено: [math]d(s) = \rho(s, s) = 0[/math]
  • Пусть для [math]n[/math] первых шагов алгоритм сработал верно и на [math]n + 1[/math] шагу выбрана вершина [math]u[/math]. Докажем, что в этот момент [math]d(u) = \rho(s, u)[/math]. Для начала отметим, что для любой вершины [math]v[/math], всегда выполняется [math]d(v) \geqslant \rho(s, v)[/math] (алгоритм не может найти путь короче, чем кратчайший из всех существующих). Пусть [math]P[/math] — кратчайший путь из [math]s[/math] в [math]u[/math], [math]v[/math] — первая непосещённая вершина на [math]P[/math], [math]z[/math] — предшествующая ей (следовательно, посещённая). Поскольку путь [math]P[/math] кратчайший, его часть, ведущая из [math]s[/math] через [math]z[/math] в [math]v[/math], тоже кратчайшая, следовательно [math]\rho(s, v) = \rho(s, z) + w(zv)[/math]. По предположению индукции, в момент посещения вершины [math]z[/math] выполнялось [math]d(z) = \rho(s, z)[/math], следовательно, вершина [math]v[/math] тогда получила метку не больше чем [math]d(z) + w(zv) = \rho(s, z) + w(zv) = \rho(s, v)[/math], следовательно, [math]d(v) = \rho(s, v)[/math]. С другой стороны, поскольку сейчас мы выбрали вершину [math]u[/math], её метка минимальна среди непосещённых, то есть [math]d(u) \leqslant d(v) = \rho(s, v) \leqslant \rho(s, u)[/math], где второе неравенсто верно из-за ранее упомянутого определения вершины [math]v[/math] в качестве первой непосещённой вершины на [math]P[/math], то есть вес пути до промежуточной вершины не превосходит веса пути до конечной вершины вследствие неотрицательности весовой функции. Комбинируя это с [math]d(u) \geqslant \rho(s, u)[/math], имеем [math]d(u) = \rho(s, u)[/math], что и требовалось доказать.
  • Поскольку алгоритм заканчивает работу, когда все вершины посещены, в этот момент [math]d(u) = \rho(s, u)[/math] для всех [math]u[/math].
[math]\triangleleft[/math]

Оценка сложности

В реализации алгоритма присутствует функция выбора вершины с минимальным значением [math]d[/math] и релаксация по всем рёбрам для данной вершины. Асимптотика работы зависит от реализации.

Пусть [math]n[/math] - количество вершин в графе, [math]m[/math] - количество рёбер в графе.

Время работы Описание
Поиск минимума Релаксация Общее
Наивная реализация [math]O(n)[/math] [math]O(1)[/math] [math]O(n^2 + m)[/math] [math]n[/math] раз осуществляем поиск вершины с минимальной величиной [math]d[/math] среди [math]O(n)[/math] непомеченных вершин и [math]m[/math] раз проводим релаксацию за [math]O(1)[/math]. Для плотных графов ([math]m \approx n^2[/math]) данная асимптотика является оптимальной.
Двоичная куча [math]O(\log{n})[/math] [math]O(\log{n})[/math] [math]O(m\log{n})[/math] Используя двоичную кучу можно выполнять операции извлечения минимума и обновления элемента за [math]O(\log{n})[/math]. Тогда время работы алгоритма Дейкстры составит [math]O(n\log{n} + m\log{n}) = O(m\log{n})[/math].
Фибоначчиева куча [math]O(\log{n})[/math] [math]O(1)[/math] [math]O(n\log{n} + m)[/math] Используя Фибоначчиевы кучи можно выполнять операции извлечения минимума за [math]O(\log{n})[/math] и обновления элемента за [math]O(1)[/math]. Таким образом, время работы алгоритма составит [math]O(n\log{n} + m)[/math].

Источники информации