Алгоритм Левита — различия между версиями
Lehanyich (обсуждение | вклад) |
Lehanyich (обсуждение | вклад) |
||
| Строка 17: | Строка 17: | ||
* <tex>v \in M_2</tex>, то <tex>v</tex> переводится в конец очереди <tex>M_1^{'}</tex>. При этом <tex>d_v \gets d_u + w_{uv}</tex> (производится релаксация ребра <tex>uv</tex>), | * <tex>v \in M_2</tex>, то <tex>v</tex> переводится в конец очереди <tex>M_1^{'}</tex>. При этом <tex>d_v \gets d_u + w_{uv}</tex> (производится релаксация ребра <tex>uv</tex>), | ||
* <tex>v \in M_1</tex>, то происходит релаксация ребра <tex>uv</tex>, | * <tex>v \in M_1</tex>, то происходит релаксация ребра <tex>uv</tex>, | ||
| − | * <tex>v \in M_0</tex> | + | * <tex>v \in M_0</tex>. Если при этом <tex>d_v > d_u + w_{uv}</tex>, то происходит релаксация ребра <tex>uv</tex> и вершина <tex>v</tex> помещается в <tex>M_1^{''}</tex>; иначе ничего не делаем. |
В конце шага помещаем вершину <tex>u</tex> в множество <tex>M_0</tex>. | В конце шага помещаем вершину <tex>u</tex> в множество <tex>M_0</tex>. | ||
| Строка 64: | Строка 64: | ||
== Сложность == | == Сложность == | ||
| − | В плохих случаях алгоритм Левита работает | + | В плохих случаях алгоритм Левита работает за экспоненциальное время. Рассмотрим граф с <tex>3\cdot n</tex> вершинами и такими рёбрами: от вершины <tex>1</tex> до <tex>n</tex> ребро веса <tex>2^n</tex>, цепь <tex>n-1</tex> рёбер через одну вершину (<tex>n</tex>, <tex>n+2</tex> <tex>...</tex> <tex>3 \cdot n</tex>; вес <tex>i</tex>-ого звена <tex>2^{n-i}</tex>), а также цепь рёбер от <tex>1</tex> до <tex>3 \cdot n</tex> (вес каждого звена <tex>0</tex>). Ясно, что кратчайший путь до каждой вершины равен <tex>0</tex>, но в плохом случае алгоритм будет постепенно улучшать расстояние до последней вершины, пересчитывая его огромное число раз, что даёт экспоненциальное время. Однако, на реальных графах алгоритм Левита работает быстрее, чем алгоритм [[Алгоритм Форда-Беллмана|Форда Беллмана]] и не многим уступает алгоритму [[Алгоритм Дейкстры|Дейкстры]]. |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
==См. также== | ==См. также== | ||
Версия 14:04, 8 ноября 2015
Алгоритм Левита (англ. Levit's algorithm) находит расстояние от заданной вершины до всех остальных. Позволяет работать с ребрами отрицательного веса при отсутствии отрицательных циклов.
Алгоритм
Пусть — текущая длина кратчайшего пути до вершины . Изначально, все элементы , кроме -го равны бесконечности; .
Разделим вершины на три множества:
- — вершины, расстояние до которых уже вычислено (возможно, не окончательно),
- — вершины, расстояние до которых вычисляется. Это множество в свою очередь делится на две очереди:
- — основная очередь,
- — срочная очередь;
- — вершины, расстояние до которых еще не вычислено.
Изначально все вершины, кроме помещаются в множество . Вершина помещается в множество (в любую из очередей).
Шаг алгоритма: выбирается вершина из . Если очередь не пуста, то вершина берется из нее, иначе из . Для каждого ребра возможны три случая:
- , то переводится в конец очереди . При этом (производится релаксация ребра ),
- , то происходит релаксация ребра ,
- . Если при этом , то происходит релаксация ребра и вершина помещается в ; иначе ничего не делаем.
В конце шага помещаем вершину в множество .
Алгоритм заканчивает работу, когда множество становится пустым.
Псевдокод
for .push() for and .add() while and .pop() .pop() for if .push() .remove() min() else if min() else if and .push() .remove() .add()
Доказательство
| Лемма: |
Алгоритм отработает за конечное время |
| Доказательство: |
| Не теряя общности, будем считать, что граф связен. Тогда алгоритм завершит работу, когда в окажутся все вершины. Так как в исходном графе нет отрицательных циклов, то для каждой вершины существует кратчайший путь. Тогда расстояние до каждой вершины может уменьшится только конечное число раз и, как следствие, вершина будет переведена из в тоже конечное число раз. С другой стороны, на каждом шаге текущая вершина гарантированно помещается в . Тогда за конечное число шагов все вершины окажутся в . |
| Лемма: |
В конце работы алгоритма не найдется такое ребро , что его релаксация будет успешной |
| Доказательство: |
|
Предположим обратное. Тогда рассмотрим 2 случая:
|
Из двух предыдущих лемм напрямую следует корректность алгоритма.
Сложность
В плохих случаях алгоритм Левита работает за экспоненциальное время. Рассмотрим граф с вершинами и такими рёбрами: от вершины до ребро веса , цепь рёбер через одну вершину (, ; вес -ого звена ), а также цепь рёбер от до (вес каждого звена ). Ясно, что кратчайший путь до каждой вершины равен , но в плохом случае алгоритм будет постепенно улучшать расстояние до последней вершины, пересчитывая его огромное число раз, что даёт экспоненциальное время. Однако, на реальных графах алгоритм Левита работает быстрее, чем алгоритм Форда Беллмана и не многим уступает алгоритму Дейкстры.
См. также
- Алгоритм A*
- Алгоритм Дейкстры
- Алгоритм Джонсона
- Алгоритм Флойда
- Алгоритм Форда-Беллмана
- Обход в ширину
Источники информации
- Википедия — Алгоритм Левита
- MAXimal :: algo :: Алгоритм Левита
- И. В. Романовский, Дискретный анализ, ISBN 5-7940-0138-0; 2008 г., 4 издание, стр. 229-231.