Случай отрицательных циклов

Алгоритм Флойда-Уоршелла нахождения кратчайших путей между всеми парами вершин

Дан ориентированный или неориентированный взвешенный граф G с
n вершинами. Требуется найти значения всех величин D[i,j] — длины кратчайшего пути из вершины i в вершину j.

Предполагается, что граф не содержит циклов отрицательного веса (тогда ответа между некоторыми парами вершин может просто не существовать — он будет бесконечно маленьким).

Идея

Пробуем улучшить путь (существующий или несуществующий) между вершинами i и jчерез вершинуk.

Реализация

На вход программе подаётся граф, заданный в виде матрицы смежности — двумерного массива D[i,j] размера , в котором каждый элемент задаёт длину ребра между соответствующими вершинами.

Требуется, чтобы выполнялось D[i, i]=0 для любых i.

for k:=1 to n do

for i:=1 to n do

for j:=1 to n do

d[i, j] = min (d[i, j], d[i, k] + d[k, j]);

Предполагается, что если между двумя какими-то вершинами нет ребра, то в матрице смежности было записано какое-то большое число (достаточно большое, чтобы оно было больше длины любого пути в этом графе); тогда это ребро всегда будет невыгодно брать, и алгоритм сработает правильно.

Правда, если не принять специальных мер, то при наличии в графе рёбер отрицательного веса, в результирующей матрице могут появиться числа вида , , и т.д., которые, конечно, по-прежнему означают, что между соответствующими вершинами вообще нет пути. Поэтому при наличии в графе отрицательных рёбер алгоритм Флойда лучше написать так, чтобы он не выполнял переходы из тех состояний, в которых уже стоит "нет пути":

const INF=maxlongint;

for k:=1 to n do

for i:=1 to n do

for j:=1 to n do

if (d[i, k] < INF) and (d[k, j] < INF)

d[i, j] = min (d[i, j], d[i, k] + d[k, j]);

Восстановление самих путей

Легко поддерживать дополнительную информацию — так называемых "предков", по которым можно будет восстанавливать сам кратчайший путь между любыми двумя заданными вершинами в виде последовательности вершин.

Для этого достаточно кроме матрицы расстояний D[i, j] поддерживать также матрицу предков Pr[i,j], которая для каждой пары вершин будет содержать номер вершины k, через которую было получено кратчайшее расстояние между ними. Теперь нам просто надо найти кратчайший путь между вершинами i и Pr[i, j], а также между Pr[i, j]и j. Отсюда получается простой рекурсивный алгоритм восстановления кратчайшего пути.

Случай вещественных весов

Если веса рёбер графа не целочисленные, а вещественные, то следует учитывать погрешности, неизбежно возникающие при работе с типами с плавающей точкой.

Применительно к алгоритму Флойда неприятным спецэффектом этих погрешностей становится то, что найденные алгоритмом расстояния могут уйти сильно в минус из-за накопившихся ошибок. В самом деле, если на первой фазе имела место ошибка , то на второй итерации эта ошибка уже может превратиться в 2, на третьей — в 4, и так далее.

Чтобы этого не происходило, сравнения в алгоритме Флойда следует делать с учётом погрешности:

if (d[i, k] + d[k, j] < d[i, j] - EPS)

d[i, j] = d[i, k] + d[k, j];

ВНИМАНИЕ!!! ЗначениеEPS зависит от условия задачи. Например, если в задаче указано, что ваш ответ может отличаться от ответа жюри на 103, то EPS=104.

Случай отрицательных циклов

Если в графе есть циклы отрицательного веса, то формально алгоритм Флойда-Уоршелла неприменим к такому графу.

На самом же деле, для тех пар вершин i и j, между которыми нельзя зайти в цикл отрицательного вес, алгоритм отработает корректно.

Для тех же пар вершин, ответа для которых не существует (по причине наличия отрицательного цикла на пути между ними), алгоритм Флойда найдёт в качестве ответа какое-то число (возможно, сильно отрицательное, но не обязательно). Тем не менее, можно улучшить алгоритм Флойда, чтобы он аккуратно обрабатывал такие пары вершин и выводил для них, например, -.

Для этого можно сделать, например, следующий критерий "не существования пути". Итак, пусть на данном графе отработал обычный алгоритм Флойда. Тогда между вершинами i иj не существует кратчайшего пути тогда и только тогда, когда найдётся такая вершина t, достижимая из i и из которой достижима j, для которой выполняется D[t, t]<0.

Кроме того, при использовании алгоритма Флойда для графов с отрицательными циклами следует помнить, что возникающие в процессе работы расстояния могут сильно уходить в минус. Поэтому следует принять меры против целочисленного переполнения, ограничив все расстояния снизу какой-нибудь величиной (например,
-INF).