Статья Автор: Деникина Н.В., Деникин А.В.

Кратчайший путь в графе из файла — Отрицательные веса

Чего мы не взяли и почему

Есть третий известный алгоритм — Дейкстра. Его знают все, и на этом задании он тоже работает. Но в наш модуль он не попал, и стоит объяснить, почему.


Как устроена Дейкстра

Она берёт вершину с наименьшим рекордом и объявляет его окончательным: короче до неё уже не будет. Потом раздаёт улучшения соседям и переходит к следующей ближайшей.

Рассуждение держится на том, что все веса положительные — любой обходной путь только прибавляет к сумме.

Где она ломается

Появилось хоть одно отрицательное ребро — и в закрытую вершину можно вернуться дешевле. Но она закрыта, и Дейкстра туда не вернётся.

Дейкстра закрывает вершину навсегда — в этом её слабое место.

Форд–Беллман не закрывает ничего. Улучшение может прийти хоть на сотом проходе, и он его примет. Флойд тоже спокойно переживает отрицательные веса.

Что при этом не меняется

Программа из третьей тетради остаётся ровно той же, ни одной новой строки. Отрицательные веса Форду–Беллману просто не мешают.

Кратчайшего пути не существует лишь в одном случае: если по кругу можно пройти и стать дешевле. Но круг — это цикл, а в нашем графе циклов нет по условию, так что проверять нечего.


Как Дейкстра работает, пока веса положительные

Золотое кольцо — вершина обработана, её рекорд больше не изменится. На шагах 3 и 4 заметь: рекорд сотни переписывается дважды, пока её саму не взяли в обработку.


7.01.05.52.012.02.58.01.0671410012вершинарекорд10000004—2.52.52.52.52.56——————7—5.55.55.55.55.512————8.58.5100—12.010.57.57.57.5Старт: рекорд есть только у вершины 1.Берём 1 — самый маленький рекорд. Раздаём соседям: 4, 7 и 100.Ближайшая необработанная — 4 (2.5). Через неё до 100 выходит 10.5.Теперь 7 (5.5). До 100 стало 7.5 — снова лучше.Берём 100 с рекордом 7.5. Он окончательный: меньше уже неоткуда.Осталась 12. Необработанных с рекордами нет — конец. Ответ 7.

Золотое кольцо — вершина обработана, её рекорд уже не изменится.


Граф, на котором Дейкстра врёт

Четыре вершины, одно отрицательное ребро. Запустим на нём Дейкстру и Форда–Беллмана подряд.



Что печатает демонстрация
[(1, 7, 2.0), (1, 4, 5.0), (4, 7, -4.0), (7, 100, 1.0)]
Дейкстра: 3.0
Форд-Беллман: 2.0

Дейкстра взяла вершину 7 с рекордом 2.0 и закрыла её. Потом дошла до вершины 4 и увидела ребро весом −4.0: через него до семёрки было бы всего 1.0, а до сотни 2.0. Но семёрка уже закрыта, и рекорд сотни остался 3.0.

Форд–Беллман ничего не закрывал и на следующем проходе спокойно нашёл 2.0.


Что делает каждая строка основной программы
строкачто делает
used.append(v)Дейкстра закрывает вершину — сюда она больше не вернётся
for step in range(1000)Форд–Беллман не закрывает ничего и проходит список заново
min(dist[j], dist[i] + w)строка улучшения не меняется: минус в весе ей безразличен
float(w)минус разбирается сам, отдельной обработки не нужно


Что печатает программа
5.1999999999999975
5

Это дословно программа из третьей тетради, в ней не изменено ни одного символа. Четырнадцать рёбер из тридцати четырёх отрицательные, и она этого даже не заметила.

Длина пути вышла положительной, хотя веса в основном отрицательные. Так и задумано: у отрицательных чисел целая часть считается вниз, и вопрос «целая часть от −5.2» превратился бы в спор о терминах.


Ловушки

  • Взяли Дейкстру, потому что она быстрее. С отрицательным ребром она молча выдаёт неверное число.
  • Начали переписывать Форда–Беллмана под отрицательные веса. Он и так работает, менять нечего.
  • Решили, что при отрицательных весах кратчайшего пути может не быть. В ациклическом графе он есть всегда.
  • Забыли, что целая часть отрицательного числа считается вниз.

Граф-контрпример: целая часть длины кратчайшего пути из вершины 1 в вершину 100.

Файл negA.txt: целая часть длины кратчайшего пути из вершины 1 в вершину 100.

По графу-контрпримеру отметьте, что верно.
Загрузка...
Чтобы оставить комментарий, необходимо авторизоваться
💬
Пока нет комментариев. Будьте первым!
Печать