Проанализируйте алгоритм Дейкстры на графе с отрицательными весами: объясните, почему алгоритм даёт некорректный результат, и предложите альтернативы для работы с такими графами
Коротко: Дейкстра некорректен на графах с отрицательными рёбрами, потому что его инвариант «как только вершина извлечена — расстояние до неё окончательное» нарушается: более короткий путь с отрицательным ребром может появиться позже и снизить расстояние до уже «зафиксированной» вершины. Пример (минимальный). Вершины s,u,vs,u,vs,u,v и рёбра: s→u\;s\to us→u вес 2\;22, s→v\;s\to vs→v вес 1\;11, u→v\;u\to vu→v вес −2-2−2. Изначально d(s)=0, d(u)=2, d(v)=1d(s)=0,\;d(u)=2,\;d(v)=1d(s)=0,d(u)=2,d(v)=1. Дейкстра извлекает vvv (так как 1<21<21<2) и помечает его окончательным. Но путь s→u→vs\to u\to vs→u→v даёт расстояние 2+(−2)=02+(-2)=02+(−2)=0, что меньше 111. Поскольку vvv уже зафиксирован, алгоритм не учтёт это улучшение — результат неверен. Ключевая причина формально: Дейкстра опирается на то, что для любого извлечённого вершина xxx и любого пути через ещё не обработанные вершины расстояние через них не может быть меньше d(x)d(x)d(x). Это верно только если все веса неотрицательны. Что делать с негативными весами — альтернативы: - Bellman–Ford: - Работает при отрицательных весах и обнаруживает отрицательные циклы, достижимые из источника. - Сложность O(VE)\;O(VE)O(VE). - Используйте, если нужен один источник и есть отрицательные веса. - SPFA (очередной вариант Bellman–Ford с улучшениями): - Часто быстрее на практике, но в худшем случае может быть экспоненциальным или O(VE)\;O(VE)O(VE). - Ненадёжен в злонамеренных случаях; полезен для практических задач, но с осторожностью. - Johnson для всех-пар кратчайших путей: - Сначала запускает Bellman–Ford от фиктивной вершины, чтобы получить потенциалы h(v)h(v)h(v) (проверяет отрицательные циклы). Затем перевзвешивает рёбра w′(u,v)=w(u,v)+h(u)−h(v)w'(u,v)=w(u,v)+h(u)-h(v)w′(u,v)=w(u,v)+h(u)−h(v) — все w′w'w′ неотрицательны — и запускает Dijkstra из каждой вершины. - Сложность примерно O(VE+V⋅(Dijkstra))\;O(VE + V\cdot (\text{Dijkstra}))O(VE+V⋅(Dijkstra)) (для разреженных графов выгодно). - Floyd–Warshall: - Для всех пар, проста в реализации, поддерживает отрицательные веса и обнаруживает отрицательные циклы. - Сложность O(V3)\;O(V^3)O(V3) — подходит для небольших VVV. Дополнительно: - Если в графе есть отрицательные циклы, достижимые из источника, то кратчайшие пути не определены (стягиваются в −∞-\infty−∞). Любой алгоритм должен либо обнаружить такие циклы (Bellman–Ford, Floyd–Warshall), либо сообщить об их существовании. - Если все веса неотрицательны, Дейкстра остаётся оптимальным выбором по эффективности. Резюме: для графов с отрицательными весами используйте Bellman–Ford (для одного источника) или Johnson/Floyd–Warshall (для всех пар); SPFA — практическая оптимизация с оговорками.
Пример (минимальный). Вершины s,u,vs,u,vs,u,v и рёбра:
s→u\;s\to us→u вес 2\;22, s→v\;s\to vs→v вес 1\;11, u→v\;u\to vu→v вес −2-2−2.
Изначально d(s)=0, d(u)=2, d(v)=1d(s)=0,\;d(u)=2,\;d(v)=1d(s)=0,d(u)=2,d(v)=1. Дейкстра извлекает vvv (так как 1<21<21<2) и помечает его окончательным. Но путь s→u→vs\to u\to vs→u→v даёт расстояние 2+(−2)=02+(-2)=02+(−2)=0, что меньше 111. Поскольку vvv уже зафиксирован, алгоритм не учтёт это улучшение — результат неверен.
Ключевая причина формально: Дейкстра опирается на то, что для любого извлечённого вершина xxx и любого пути через ещё не обработанные вершины расстояние через них не может быть меньше d(x)d(x)d(x). Это верно только если все веса неотрицательны.
Что делать с негативными весами — альтернативы:
- Bellman–Ford:
- Работает при отрицательных весах и обнаруживает отрицательные циклы, достижимые из источника.
- Сложность O(VE)\;O(VE)O(VE).
- Используйте, если нужен один источник и есть отрицательные веса.
- SPFA (очередной вариант Bellman–Ford с улучшениями):
- Часто быстрее на практике, но в худшем случае может быть экспоненциальным или O(VE)\;O(VE)O(VE).
- Ненадёжен в злонамеренных случаях; полезен для практических задач, но с осторожностью.
- Johnson для всех-пар кратчайших путей:
- Сначала запускает Bellman–Ford от фиктивной вершины, чтобы получить потенциалы h(v)h(v)h(v) (проверяет отрицательные циклы). Затем перевзвешивает рёбра w′(u,v)=w(u,v)+h(u)−h(v)w'(u,v)=w(u,v)+h(u)-h(v)w′(u,v)=w(u,v)+h(u)−h(v) — все w′w'w′ неотрицательны — и запускает Dijkstra из каждой вершины.
- Сложность примерно O(VE+V⋅(Dijkstra))\;O(VE + V\cdot (\text{Dijkstra}))O(VE+V⋅(Dijkstra)) (для разреженных графов выгодно).
- Floyd–Warshall:
- Для всех пар, проста в реализации, поддерживает отрицательные веса и обнаруживает отрицательные циклы.
- Сложность O(V3)\;O(V^3)O(V3) — подходит для небольших VVV.
Дополнительно:
- Если в графе есть отрицательные циклы, достижимые из источника, то кратчайшие пути не определены (стягиваются в −∞-\infty−∞). Любой алгоритм должен либо обнаружить такие циклы (Bellman–Ford, Floyd–Warshall), либо сообщить об их существовании.
- Если все веса неотрицательны, Дейкстра остаётся оптимальным выбором по эффективности.
Резюме: для графов с отрицательными весами используйте Bellman–Ford (для одного источника) или Johnson/Floyd–Warshall (для всех пар); SPFA — практическая оптимизация с оговорками.