Почему алгоритм кратчайшего пути Dijkstra на основе приоритетов не может работать для графика отрицательных весов? [Дубликат]

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
83
задан nbro 15 August 2015 в 14:31
поделиться

5 ответов

Напомним, что в алгоритме Дейкстры, как только вершина отмечена как «закрытая» (и вне открытого набора), алгоритм нашел кратчайший путь к ней, и ему никогда не придется развить этот узел снова - он предполагает путь разработанный на этот путь, является самым коротким.

Но с отрицательными весами это может быть неверно. Например:

       A
      / \
     /   \
    /     \
   5       2
  /         \
  B--(-10)-->C

V={A,B,C} ; E = {(A,C,2), (A,B,5), (B,C,-10)}

Dijkstra из A сначала разработает C и позже не найдет A->B->C


EDIT немного более глубокое объяснение:

Обратите внимание, что это важно, потому что на каждом этапе релаксации алгоритм предполагает, что «стоимость» для «закрытых» узлов действительно минимальна, и, следовательно, следующий узел будет также минимальным.

Идея заключается в следующем: если у нас есть открытая вершина, такая, что ее стоимость минимальна - добавлением любого положительного числа в любую вершину - минимальность никогда не изменится. Без ограничения на положительные числа - вышеприведенное предположение неверно.

Поскольку мы «знаем», каждая вершина, которая была «закрыта», минимальна - мы можем безопасно сделать шаг релаксации - без «оглядки», , Если нам нужно «оглянуться назад» - Bellman-Ford предлагает рекурсивное (DP) решение.

116
ответ дан amit 17 August 2018 в 21:24
поделиться
  • 1
    Извините, но я не получаю никаких ошибок. Сначала A->B будет 5 и A->C равно 2. Тогда B->C будет -5. Таким образом, значение C будет -5 таким же, как bellman-ford. Как это не дает правильного ответа? – Anirban Nag 'tintinmj' 23 May 2014 в 08:02
  • 2
    Сначала @tintinmj, Dijkstra «закрывается». node A со значением 0. Затем он будет смотреться на узле с наименьшими значениями, B равен 5, а C равно 2. Минимальное значение C, поэтому оно закроет C со значением 2 и никогда не оглядывается назад, когда позже B закрывается, он не может изменить значение C, так как он уже «закрыт». – amit 23 May 2014 в 09:33
  • 3
    @amit Как алгоритм Дейкстры не найдет путь A -> B -> C? Он сначала обновит расстояние C до 2, а затем расстояние B до 5. Предполагая, что на вашем графике нет исходящих ребер из C, тогда мы ничего не делаем при посещении C (и его расстояние еще 2). Затем мы посещаем соседние узлы D, а единственным соседним узлом является C, новое расстояние которого -5. Обратите внимание, что в алгоритме Дейкстры мы также отслеживаем родительский элемент, из которого мы достигаем (и обновляем) узел, и делаем это из C, вы получите родительский B, а затем A, в результате чего правильный результат. Что мне не хватает? – nbro 15 August 2015 в 15:10
  • 4
    @amit Проблема с вашими рассуждениями (я думаю), и я видел, как другие люди это делали (как это ни странно), так это то, что вы считаете, что алгоритм не будет пересматривать узлы, кратчайшее расстояние которых уже определено (и что мы сделали) но это неверно, и именно поэтому у нас есть «релаксация». шаг ... Мы перебираем все узлы графа, и для каждого из них мы итерации через соседние узлы, даже если любой из соседних узлов, возможно, уже был удален из нашей очереди с минимальным приоритетом, например. – nbro 15 August 2015 в 15:46
  • 5
    @amit Проверьте этот ответ на аналогичный вопрос, где пример действительно имеет смысл: stackoverflow.com/a/6799344/3924118 – nbro 15 August 2015 в 15:51

Рассмотрим график, показанный ниже, с источником как Vertex A. Сначала попробуйте запустить сам алгоритм Дейкстры.

enter image description here [/g16]

Когда я говорю о Dijkstra's алгоритм в моем объяснении, я расскажу об алгоритме Дейкстры, как это реализовано ниже,

Dijkstra’s algorithm [/g17]

Итак, начиная значения ( расстояние от источник к вершине ), первоначально назначенный каждой вершине, являются

. Сначала мы извлекаем вершину из Q = [A, B, C], который имеет наименьшее значение, то есть A, после чего Q = [B, C]. Примечание. A имеет направленное ребро для B и C, оба из них находятся в Q, поэтому мы обновляем оба этих значения,

Теперь мы экстракт C как (2 & lt; 5), теперь Q = [B]. Обратите внимание, что C ни к чему не связан, поэтому цикл line16 не запускается.

Наконец, мы извлекаем B, после чего . Примечание B имеет направленный край к C, но C отсутствует в Q, поэтому мы снова не вводим цикл for в line16,

Итак, мы закончили с расстояниями как

Обратите внимание, как это неправильно, поскольку кратчайшее расстояние от A до C равно 5 + -10 = -5, когда вы идете .

Итак, для этого графика алгоритм Дейкстры ошибочно вычисляет расстояние от A до C.

Это происходит потому, что Алгоритм Дейкстры не попробуйте найти более короткий путь к вершинам, которые уже извлечены из Q .

То, что делает цикл line16, - это взять вершину u и сказать «эй выглядит как мы можем перейти к v из источника через u, является ли это (alt или альтернативное) расстоянием лучше, чем текущий dist [v], который мы получили? Если это так, обновите dist [v] "

Обратите внимание, что в line16 они проверяют все соседи v (т. Е. Направленное ребро существует от u до v), из u, которые все еще находятся в Q. В line14 они удаляют посещенные заметки из Q. Так что, если x является посещенным соседом u, th e path даже не рассматривается как возможный более короткий путь от источника к v.

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

Итак, я говорю, что при запуске этого алгоритма, если x извлекается из Q до y, тогда его невозможно найти путь - , который короче. Позвольте мне объяснить это с помощью примера

. Когда y только что был извлечен, и x был извлечен перед собой, тогда dist [y]> dist [x], поскольку в противном случае y было бы извлечено до x. (line 13 min distance first)

И как мы уже предположили , что веса ребер положительны, т. е. длина (x, y)> 0. Поэтому альтернативное расстояние (alt) через y всегда должно быть больше, то есть dist [y] + length (x, y)> dist [x]. Таким образом, значение dist [x] не было бы обновлено, даже если y рассматривался как путь к x, поэтому мы заключаем, что имеет смысл рассматривать только соседи y, которые все еще находятся в Q (примечание к примечанию в line16),

Но это зависит от нашего предположения о положительной длине ребра, если длина (u, v) & lt 0, то в зависимости от того, насколько отрицательно это ребро, мы могли бы заменить dist [x] после сравнения в line18.

Таким образом, любой расчет dist [x], который мы делаем, будет некорректным, если x удаляется до того, как все вершины v - такие, что x является соседним v с отрицательным ребрами, соединяющим их - удаляется.

Поскольку каждая из этих v вершин является второй последней вершиной на потенциальном «лучшем» пути от источника к x, который отбрасывается алгоритмом Дейкстры.

Итак, в примере Я сказал выше, ошибка заключалась в том, что C был удален до того, как B был удален. В то время как C был соседом B с отрицательным ребром!

Чтобы уточнить, B и C являются соседями А. B имеет один соседний C и C не имеет соседей. length (a, b) - длина ребра между вершинами a и b.

27
ответ дан Aditya 17 August 2018 в 21:24
поделиться
  • 1
    Как вы сказали, лучший способ решить это - использовать метод heapq.heappush после каждого сравнения. Мы возвращаем обновленное расстояние в очередь. При этом условии Дейкстра может работать на отрицательных весах. Я попытался, и результат получился как 0,5, -5 – nosense 25 November 2017 в 22:39

Попробуйте алгоритм Дейкстры на следующем графике, предполагая, что A является исходным узлом, чтобы увидеть, что происходит:

Graph [/g0]

3
ответ дан nbro 17 August 2018 в 21:24
поделиться
  • 1
    Извините, но я не получаю никаких ошибок. Сначала A->B будут 1 и A->C будут 100. Тогда B->D будет 2. Тогда C->D будет -4900. Таким образом, значение D будет -4900 таким же, как bellman-ford. Как это не дает правильного ответа? – Anirban Nag 'tintinmj' 23 May 2014 в 00:11
  • 2
    – Christian Schnorr 16 July 2014 в 15:46
  • 3
    @ tb- Извините за вопрос после такого долгого времени, но я здесь, на правильном пути? Сначала A->B будет 1, а A->C будет 100. Затем исследуется B и устанавливает B->D на 2. Затем исследуется D , потому что в настоящее время он имеет самый короткий путь назад к источнику? Правильно ли я сказал бы, что если B->D был 100, C был бы изучен первым? Я понимаю все другие примеры, которые люди дают, кроме твоих. – Pejman Poh 8 February 2017 в 01:40
  • 4
    @PejmanPoh из моего понимания, если B- & gt; D равно 100, так как A- & gt; C выше в HeapStructure, который будет использоваться, миндальный экстракт сначала вернет A- & gt; C, что означает, что следующий найденный самый короткий путь будет - путь к C, после чего путь от C- & gt; D, который имеет вес -5000, будет очевидным выбором, что приведет нас к выводу, что кратчайший путь будет от A- & gt; C- & gt; D и я уверен, что это будет нормальное поведение. Поэтому иногда, когда у нас есть отрицательные циклы, мы все равно можем получить правильное значение для кратчайшего пути, но определенно не всегда, это пример, где мы не будем .. – T.Dimitrov 17 August 2018 в 10:07

Правильность алгоритма Дейкстры:

У нас есть два набора вершин на любом шаге алгоритма. Набор А состоит из вершин, на которые мы вычислили кратчайшие пути. Множество B состоит из оставшихся вершин.

Индуктивная гипотеза: на каждом шаге мы будем считать, что все предыдущие итерации верны.

Индуктивный шаг: когда мы добавляем вершину V в множество A и задайте расстояние до dist [V], мы должны доказать, что это расстояние оптимально. Если это не оптимально, то должен существовать некоторый другой путь к вершине V, которая имеет более короткую длину.

Предположим, что какой-то другой путь проходит через некоторую вершину X.

Теперь, поскольку dist [V] & lt; = dist [X], поэтому любой другой путь к V будет иметь длину по крайней мере dist [V], если граф не имеет отрицательных длин ребер.

Таким образом, для работы алгоритма dijkstra веса ребер должны быть не отрицательными.

5
ответ дан Nikunj Banka 17 August 2018 в 21:24
поделиться

Алгоритм Дейкстры предполагает, что пути могут только стать «более тяжелыми», так что если у вас есть путь от А до В с весом 3 и путь от А до С с весом 3, вы не можете добавить ребро и получить от A до B через C с весом менее 3.

Это предположение делает алгоритм быстрее, чем алгоритмы, которые должны принимать отрицательные веса.

15
ответ дан zmbq 17 August 2018 в 21:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: