it-roy-ru.com

Отрицательные веса с использованием алгоритма Дейкстры

Я пытаюсь понять, почему алгоритм Дейкстры не будет работать с отрицательными весами. Читая пример Кратчайших путей , я пытаюсь выяснить следующий сценарий:

    2
A-------B
 \     /
3 \   / -2
   \ /
    C

С веб-сайта:

Предполагая, что все ребра направлены слева направо, если мы начнем с A, алгоритм Дейкстры выберет Edge (A, x), минимизирующий d (A, A) + length (Edge), а именно (A, B). Затем он устанавливает d (A, B) = 2 и выбирает другой Edge (y, C), минимизируя d (A, y) + d (y, C); единственный выбор - (A, C), и он устанавливает d (A, C) = 3. Но он никогда не находит кратчайший путь от A до B через C, общей длиной 1.

Я не могу понять, почему при использовании следующей реализации Dijkstra d [B] не будет обновлен до 1 (Когда алгоритм достигает вершины C, он запускает ослабление на B, видит, что d [B] равен 2, и поэтому обновите его значение до 1).

Dijkstra(G, w, s)  {
   Initialize-Single-Source(G, s)
   S ← Ø
   Q ← V[G]//priority queue by d[v]
   while Q ≠ Ø do
      u ← Extract-Min(Q)
      S ← S U {u}
      for each vertex v in Adj[u] do
         Relax(u, v)
}

Initialize-Single-Source(G, s) {
   for each vertex v  V(G)
      d[v] ← ∞
      π[v] ← NIL
   d[s] ← 0
}

Relax(u, v) {
   //update only if we found a strictly shortest path
   if d[v] > d[u] + w(u,v) 
      d[v] ← d[u] + w(u,v)
      π[v] ← u
      Update(Q, v)
}

Спасибо,

Меир

104
Meir

Алгоритм, который вы предложили, действительно найдет кратчайший путь в этом графе, но не во всех графах в целом. Например, рассмотрим этот график:

Figure of graph

Предположим, что края направлены слева направо, как в вашем примере,

Ваш алгоритм будет работать следующим образом:

  1. Сначала вы устанавливаете d(A) на zero, а остальные расстояния на infinity.
  2. Затем вы расширяете узел A, устанавливая d(B) в 1, d(C) в zero и d(D) в 99.
  3. Затем вы расширяете C без изменений в сети.
  4. Затем вы расширяете B, что не имеет никакого эффекта.
  5. Наконец, вы расширяете D, который меняет d(B) на -201.

Однако обратите внимание, что в конце этого d(C) по-прежнему 0, хотя кратчайший путь к C имеет длину -200. Таким образом, в некоторых случаях ваш алгоритм не может точно вычислить расстояния. Более того, даже если бы вы сохраняли указатели, указывающие, как добраться от каждого узла до начального узла A, вы бы прекратили возвращаться по неверному пути из C в A.

186
templatetypedef

Обратите внимание, что Дейкстра работает даже для отрицательных весов, если в графе нет отрицательных циклов, то есть циклов, у которых суммарный вес меньше нуля.

Конечно, можно спросить, почему в примере, созданном с помощью templatetypedef, Дейкстра терпит неудачу, даже если нет отрицательных циклов, даже не циклов. Это потому, что он использует другой критерий остановки, который содержит алгоритм, как только целевой узел достигнут (или все узлы были рассчитаны один раз, он не указал это точно). На графике без отрицательных весов это работает нормально.

Если использовать альтернативный критерий остановки, который останавливает алгоритм, когда очередь приоритетов (куча) пустует (этот критерий остановки также использовался в вопросе), тогда dijkstra найдет правильное расстояние даже для графиков с отрицательными весами, но без отрицательные циклы.

Однако в этом случае асимптотическая временная граница Дейкстры для графов без отрицательных циклов теряется. Это связано с тем, что ранее установленный узел может быть повторно вставлен в кучу, когда найдено лучшее расстояние из-за отрицательных весов. Это свойство называется исправлением метки.

20
infty10000101

вы нигде не использовали S в своем алгоритме (помимо его изменения). идея dijkstra - это когда вершина находится на S, она никогда не будет изменена. в этом случае, если B находится внутри S, вы не достигнете его снова через C.

этот факт обеспечивает сложность O (E + VlogV) [в противном случае вы будете повторять ребра более одного раза, а вершины - более одного раза]

другими словами, алгоритм, который вы разместили, может быть не в O (E + VlogV), как обещал алгоритм Дейкстры.

9
amit

Поскольку Dijkstra является подходом Greedy, после того, как вершина помечается как посещенная для этого цикла, она никогда не будет переоценена снова, даже если есть другой путь с меньшими затратами для его достижения в дальнейшем. И такая проблема может возникнуть только при наличии отрицательных ребер на графике.


жадный алгоритм , как следует из названия, всегда делает выбор, который кажется лучшим в данный момент. Предположим, что у вас есть целевая функция, которую необходимо оптимизировать (максимизировать или минимизировать) в заданной точке. алгоритм Greedy делает жадный выбор на каждом шаге для обеспечения оптимизации целевой функции. Алгоритм Жадного имеет только один выстрел для вычисления оптимального решения так что он никогда не возвращается и не отменяет решение.

6
punchoyeah

Подумайте, что произойдет, если вы идете туда-сюда между B и C ...

(актуально только если график не направлен)

Отредактировано: я полагаю, что проблема связана с тем фактом, что путь с AC * может быть только лучше, чем AB с наличием отрицательных весовых граней, поэтому не имеет значения, куда вы идете после AC, с предположением, что Отрицательные грани веса невозможно найти путь лучше, чем AB, если вы решили достичь B после перехода AC.

1
prusswan

"2) Можем ли мы использовать алгоритм Дейксры для кратчайших путей для графов с отрицательными весами - одна идея может состоять в том, чтобы вычислить минимальное значение веса, добавить положительное значение (равное абсолютному значению минимального значения веса) ко всем весам и запустить алгоритм Дейксры. для модифицированного графа. Будет ли работать этот алгоритм?

Это абсолютно не работает, если все кратчайшие пути не имеют одинаковую длину. Например, учитывая кратчайший путь длиной два ребра и после добавления абсолютного значения к каждому ребру, общая стоимость пути увеличивается на 2 * | max отрицательный вес |. С другой стороны еще один путь длиной три ребра, поэтому стоимость пути увеличивается на 3 * | max отрицательный вес |. Следовательно, все различные пути увеличиваются в разной степени.

1
Wackyfool

TL; DR: для псевдокода, который вы разместили, он работает с отрицательными весами.


Варианты алгоритма Дейкстры

Ключ есть 3 версии алгоритма Дейкстры , но все ответы на этот вопрос игнорируют различия между этими вариантами.

  1. Использование вложенного for- цикла для расслабления вершин. Это самый простой способ реализовать алгоритм Дейкстры. Временная сложность O (V ^ 2).
  2. Реализация на основе приоритетной очереди/кучи + НЕТ повторного входа , где повторный вход означает, что расслабленная вершина может быть снова помещена в приоритетную очередь.
  3. Реализация с приоритетом очереди/кучи + повторный вход разрешен .

Версии 1 и 2 не будут работать на графиках с отрицательными весами (если вы получите правильный ответ в таких случаях, это просто совпадение), но версия 3 все еще работает .

Псевдокод, размещенный под исходным вопросом, является версией 3 выше, поэтому он работает с отрицательными весами.

Вот хорошая ссылка из Алгоритм (4-е издание) , в котором говорится (и содержит реализацию Java версий 2 и 3, о которых я упоминал выше):

В. Алгоритм Дейкстры работает с отрицательными весами?

А. Да и нет. Существует два алгоритма кратчайших путей, известных как алгоритм Дейкстры, в зависимости от того, может ли вершина ставиться в очередь с приоритетами более одного раза. Когда веса неотрицательны, две версии совпадают (поскольку ни одна вершина не будет помещена в очередь более одного раза). Версия, реализованная в DijkstraSP.Java (которая позволяет ставить вершины в очередь более одного раза), верна при наличии отрицательных весов Edge (но без отрицательных циклов), но ее время выполнения экспоненциально в худшем случае. (Мы отмечаем, что DijkstraSP.Java выдает исключение, если взвешенный по Edge орграф имеет Edge с отрицательным весом, так что программист не удивляется такому экспоненциальному поведению.) Если мы изменим DijkstraSP.Java, чтобы вершина не могла быть помещена в очередь более одного раза (например, используя помеченный массив [] для пометки тех вершин, которые были ослаблены), алгоритм гарантированно будет работать за время E log V, но он может дать неверные результаты, если есть ребра с отрицательными весами.


Для получения дополнительной информации о реализации и связи версии 3 с алгоритмом Беллмана-Форда, пожалуйста, смотрите этот ответ от zhih . Это тоже мой ответ (но на китайском). В настоящее время у меня нет времени перевести его на английский. Я действительно ценю, если кто-то может сделать это и отредактировать этот ответ на stackoverflow.

0
soloice