В этом разделе рассматриваются различные варианты одной задач. Пусть имеется n городов, пронумерованных числами от 1 до n. Для каждой пары городов с номерами i, j в таблице a[i][j] хранится целое число -- цена прямого авиабилета из города i в город j. Считается, что рейсы существуют между любыми городами, при всех i, a[i][j] может отличаться от a[j][i]. Наименьшей стоимостью проезда из i в j считается минимально возможная сумма цен билетов для маршрутов (в том числе с пересадками), ведущих из i в j. (Она не превосходит a[i][j], но может быть меньше.)
В предлагаемых ниже задачах требуется найти наименьшую стоимость проезда для некоторых пар городов при тех или иных ограничениях на массив a и на время работы алгоритма.
9.1.1. Предположим, что не существует замкнутых маршрутов, для
которых сумма цен отрицательна. Доказать, что в этом случае
маршрут с наименьшей стоимостью существует.
Во всех следующих задачах предполагается, что это условие (отсутствие циклов с отрицательной суммой) выполнено.
9.1.2. Найти наименьшую стоимость проезда из 1-го города во
все остальные за время .
k:= 1; for i := 1 to n do begin x[i] := a[1][i]; end; {инвариант: x[i] := МинСт(1,i,k)} while k <> n do begin | for s := 1 to n do begin | | y[s] := x[s]; | | for i := 1 to n do begin | | | if y[s] > x[i]+a[i][s] then begin | | | | y[s] := x[i]+a[i][s]; | | | end; | | end | | {y[s] = МинСт(1,s,k+1)} | end; | for i := 1 to n do begin x[s] := y[s]; end; | k := k + 1; end;Приведенный алгоритм называют алгоритмом динамического программирования, или алгоритмом Форда-Беллмана.
9.1.3. Доказать, что программа останется правильной, если не заводить
массива y, а производить изменения в самом массиве x
(заменив в программе все вхождения буквы y на x и затем
удалить ставшие лишними строки).
Этот алгоритм может быть улучшен в двух отношениях: можно за то же время найти наименьшую стоимость проезда для всех пар i,j (а не только при ), а можно сократить время работы до . Правда, в последнем случае нам потребуется, чтобы все цены a[i][j] были неотрицательны.
9.1.4. Найти наименьшую стоимость проезда для всех i,j
за время .
Этот алгоритм называют алгоритмом Флойда.
9.1.5. Известно, что все цены неотрицательны. Найти наименьшую
стоимость проезда для всех за время .
Множество выделенных городов расширяется на основании следующего замечания: если среди всех невыделенных городов взять тот, для которого хранимое число минимально, то это число является истинной наименьшей стоимостью. В самом деле, пусть есть более короткий путь. Рассмотрим первый невыделенный город на этом пути -- уже до него путь длиннее! (Здесь существенна неотрицательность цен.)
Добавив выбранный город к выделенным, мы должны скорректировать информацию, хранимую для невыделенных городов. При этом достаточно учесть лишь пути, в которых новый город является последним пунктом пересадки, а это легко сделать, так как минимальную стоимость проезда в новый город мы уже знаем.
При самом бесхитростном способе хранения множества выделенных городов (в булевском векторе) добавление одного города к числу выделенных требует времени .
Этот алгоритм называют алгоритмом Дейкстры.
Отыскание кратчайшего пути имеет естественную интерпретацию в терминах матриц. Пусть A -- матрица цен одной авиакомпании, а B -- матрица цен другой. Пусть мы хотим лететь с одной пересадкой, причем сначала самолетом компании A , а затем -- компании B . Сколько нам придется заплатить, чтобы попасть из города i в город j?
9.1.6. Доказать, что эта матрица вычисляется по обычной
формуле для произведения матриц, только вместо суммы надо брать
минимум, а вместо умножения -- сумму.
9.1.7. Доказать, что таким образом определенное произведение
матриц ассоциативно.
9.1.8. Доказать, что задача о кратчайших путях эквивалентна
вычислению для матрицы цен A : в последовательности
все элементы, начиная с некоторого, равны
искомой матрице стоимостей кратчайших путей. (Если нет
отрицательных циклов!)
9.1.9. Начиная с какого элемента можно гарантировать равенство в
предыдущей задаче?
Обычное (не модифицированное) умножение матриц тоже может оказаться полезным, только матрицы должны быть другие. Пусть есть не все рейсы (как раньше), а только некоторые, a[i,j] равно 1, если рейс есть, и 0, если рейса нет. Возведем матрицу a (обычным образом) в степень k и посмотрим на ее i-j-ый элемент.
9.1.10. Чему он равен?
Случай, когда есть не все рейсы, можно свести к исходному, введя фиктивные рейсы с бесконечно большой (или достаточно большой) стоимостью. Тем не менее возникает такой вопрос. Число реальных рейсов может быть существенно меньше n2 , поэтому интересны алгоритмы, которые работают эффективно в такой ситуации. Исходные данные естественно представлять тогда в такой форме: для каждого города известно число выходящих из него рейсов, их пункты назначения и цены.
9.1.11. Доказать, что алгоритм Дейкстры можно модифицировать так,
чтобы для n городов и m рейсов (всего) он требовал не более
операций.